AOP
spring的核心技术:
IoC/DI - 一个概念 控制反转 - 依赖注入。
AOP 面向切面的编程。
1:AOP简介
AOP的本质 - 就是一个超级强大,且容易配置,灵活干预的动态代理。
AOP观注的是项目中重复的代码.
2:AOP的一些概念
AOP决定做什么事 = 什么时间做 + 在哪儿做地点
切面 = 通知(前后环绕) + 切点哪一个类上哪一个方法上
Advisor = Advice + Pointcut
不需要自己开发 = 要求自己开发 + 不求自己开发
Advice
前通知BeforeAdvice
后通知AfterAdvice
AfterThrowAdvice - 异常以后通知
AfterReturningAdvice - 正确执行成功以后通知
环绕通知 MethodInterceptor 方法拦截
Pointcut切点
JdkRegexpressionMethodPointcut - 基于正则表达式的说明
AspectJExpressionPontcut
3:导入包
手工的项目:
maven:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
4:开发一个切面测试
@Test
public void test1(){
//1:声明被代理的目标对象
Person person = new Person();
//2:声明通知
Advice beforeAdvice = new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.err.println("在某个方法这前执行:"+method.getName());
}
};
//3:声明切点
AspectJExpressionPointcut cut =
new AspectJExpressionPointcut();
cut.setExpression("execution(* cn.spring..Person.say())");
//4:声明成切面
Advisor advisor = new DefaultPointcutAdvisor(cut,beforeAdvice);
//5:声明代理类
ProxyFactoryBean proxy = new ProxyFactoryBean();
//设置被代理的对象
proxy.setTarget(person);
//设置切面
proxy.addAdvisors(advisor);
//从里面获取到被代理的对象
Person pp = (Person) proxy.getObject();
pp.say();
}
5:更多通知的示例
添加一个后通知
package cn.spring.demo03;
import java.lang.reflect.Method;
import org.aopalliance.aop.Advice;
import org.junit.Test;
import org.springframework.aop.Advisor;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.aop.support.DefaultPointcutAdvisor;
public class Demo01_AOP {
@Test
public void test1(){
//1:声明被代理的目标对象
Person person = new Person();
//2:声明通知
Advice beforeAdvice = new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.err.println("在某个方法这前执行:"+method.getName());
}
};
//添加一个后通知
Advice afterAdvice = new AfterReturningAdvice() {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.err.println("某个方法执行完成:"+method.getName());
}
};
//3:声明切点
AspectJExpressionPointcut cut =
new AspectJExpressionPointcut();
cut.setExpression("execution(* cn.spring..Person.say())");
//4:声明成切面
Advisor advisor = new DefaultPointcutAdvisor(cut,beforeAdvice);
Advisor advisor2 = new DefaultPointcutAdvisor(cut, afterAdvice);
Advisor advisor3 = new DefaultPointcutAdvisor(cut,new MyThrowAdvice());
//5:声明代理类
ProxyFactoryBean proxy = new ProxyFactoryBean();
//设置被代理的对象
proxy.setTarget(person);
//设置切面
proxy.addAdvisors(advisor,advisor2,advisor3);
//从里面获取到被代理的对象
Person pp = (Person) proxy.getObject();
pp.say();
}
}
6:将代码配置到spring的配置文件中实现切面
开发发一个环绕通知:
package cn.spring.demo03;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class AroundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.err.println("方法拦截到了:" + invocation.getMethod().getName());
// 放行
Object returnValue = invocation.proceed();
System.err.println("拦截完成了..");
return returnValue;
}
}
配置:
<!-- 以下是切面 -->
<bean id="advice" class="cn.spring.demo03.AroundAdvice" />
<!-- 切点 -->
<bean id="cut"
class="org.springframework.aop.aspectj.AspectJExpressionPointcut">
<property name="expression" value="execution(* cn.spring..*.*(..))"></property>
</bean>
<bean id="advisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice" ref="advice" />
<property name="pointcut" ref="cut"></property>
</bean>
<!-- 声明对Person的代理类 -->
<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<bean class="cn.spring.demo03.Person"></bean>
</property>
<property name="interceptorNames">
<list>
<value>advisor</value>
</list>
</property>
测试:
上面的问题是:
如果一个类想被代理,则必须要配置:
<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<bean class="cn.spring.demo03.Person"></bean>
</property>
<property name="interceptorNames">
<list>
<value>advisor</value>
</list>
</property>
7:自动代理的切面
自动的代理类,默认是后处理Bean的子类:
<!-- 配置自动代理的Bean -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
使用aop命名空间:
<aop:auto-proxy/>
8:在项目中使用aop管理事务
使用模板:
Platformtransactionmanager/datasourcetransactionmanager/hiberate...
TransactionTremplate
<!-- 配置事务事务器 -->
<bean id="txm" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSouce"></property>
</bean>
<!-- 配置事务的通知 -->
<tx:advice id="txAdvice" transaction-manager="txm">
<!-- 声明对哪些方法如何管理事务 -->
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置切面 -->
<aop:config>
<aop:pointcut expression="execution(* cn.ss..service.*Service.*(..))" id="cut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="cut"/>
</aop:config>