chapter03 Spring的AOP
一、AOP(Aspect-oriented programming,面向切面编程):
什么是AOP?
定义:将程序中的交叉业务逻辑提取出来,封装成切面。然后由AOP容器的功能织入到具体的业务模块当中,然后生成一个代理对象的过程。
例如:安全,事务,日志等都属于交叉业务逻辑。他们的特点是都是通用的并且与具体的业务逻辑无关。他们往往与具体的业务逻辑交织在一起、
切面------织入----->目标对象-------生成------>AOP代理
AOP实现的方式:
1.使用特殊的编译器,直接将切面代码写入到目标对象的字节码当中,它的优点是速度快,实现困难 AspectJ
2.在目标类加载是将切面代码织入到目标对象当中,需要实现一个classloader
3.Spring的AOP实现方式:利用动态代理机制
二、AOP核心概念
1、Aspect(切面)
切面,是对交叉业务逻辑的统称。
2、Joinpoint(连接点)抽象的概念
连接点,指切面可以织入到目标对象的位置(方法,属性等)。
3、Advice(通知)
通知,指切面的具体实现。
4、Pointcut(切入点)
切入点,指通知应用到哪些类的哪些方法或属性之上的规则。(即切面具体织入的位置)
5、Introduction(引入)
引入,指动态地给一个对象增加方法或属性的一种特殊的通知。
6、Weaving(织入)
织入,指将通知插入到目标对象。
7、Target(目标对象)
目标对象,指需要织入切面的对象。
8、Proxy(代理对象)
代理对象,指切面织入目标对象之后形成的对象。
AOP采用代理模式实现的原理:
1.静态代理模式:
package aop1;
//目标对象或叫目标类
public class CustomerService implements ICustomerService{
@Override
public void register() {
System.out.println("register");
}
}
package aop1;
//代理接口
public interface ICustomerService {
public void register();
}
package aop1;
import java.util.Date;
//代理类
public class CustomerProxy implements ICustomerService{
private ICustomerService isc;
public CustomerProxy() {
super();
}
public CustomerProxy(ICustomerService isc) {
super();
this.isc = isc;
}
@Override
public void register() {
//交叉业务(切面代码),由代理类实现
System.out.println("current time is :"+new Date());
//核心业务逻辑,由目标对象来实现
isc.register();
}
}
package aop1;
public class Test {
/**
* @param args
* 客户端
* 静态代理模式
*/
public static void main(String[] args) {
ICustomerService target=new CustomerService();
ICustomerService proxy=new CustomerProxy(target);
//上面两行代码应该交给工厂去做。我们不关心得到的是目标还是代理对象
//spring当中它是交给spring容器做的
proxy.register();
}
}
2.动态代理模式:
package aop2;
//目标对象或叫目标类
public class CustomerService implements ICustomerService{
@Override
public void register() {
System.out.println("register");
}
}
package aop2;
//代理接口
public interface ICustomerService {
public void register();
}
package aop2;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Date;
//切面的代码(交叉业务逻辑),接口的作用是将切面代码织入到目标对象当中
public class LogInvocationHandler implements InvocationHandler{
private Object target;//因为这段切面不只是织入到一个目标类中
public LogInvocationHandler() {
super();
}
public LogInvocationHandler(Object target) {
super();
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
//method代表目标对象的一个方法,args目标对象方法参数的值
throws Throwable {
//切面代码
System.out.println("execute invoke" + new Date());
//执行目标对象里面的方法
System.out.println("method"+method);
Object proxy1=method.invoke(target, args);
System.out.println(proxy1);
return proxy1;
}
}
package aop2;
public class Test {
/**
* @param args
* 客户端
* 动态代理模式
*/
public static void main(String[] args) {
ICustomerService target=new CustomerService();
ICustomerService proxy=(ICustomerService) java.lang.reflect.Proxy.newProxyInstance
(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new LogInvocationHandler(target));
//参数1目标对象的类加载器,参数2目标对象所实现的业务接口,参数3切面
proxy.register();
}
}
三、Spring AOP原理
采用动态代理模式。
Spring AOP采动态代理的过程:
(1) 将切面使用动态代理的方式动态织入到目标对象(被代理类),形成一个代理对象;
(2) 目标类如果没有实现代理接口,那么Spring会采用CGLib来生成代理对象,该代理对象是目标对象的子类;此时的目标类不能是final的类。如果实现了业务接口,Spring会直接使用jdk当中的Proxy生成代理
(3) 目标对象如果是final类,并且也没实现代理接口,就不能运用AOP。
四、Spring的通知
1、Spring的通知类型
(1) MethodBeforeAdvice
类全名:org.springframework.aop.MethodBeforeAdvice
在目标方法调用之前,做处理。
不能够改变返回值
不能够改变目标方法的流程,也不能中断流程的处理过程(除非抛出异常)
(2) AfterReturningAdvice
类全名:org.springframework.aop.AfterReturningAdvice
在方法调用之后,做处理。
不能够改变返回值
不能够改变目标方法的流程,也不能中断流程的处理过程(除非抛出异常)
(3) MethodInterceptor:拦截器
类全名:org.aopalliance.intercept.MethodInterceptor
在方法调用之前以及之后,做处理。
可以改变返回值,也可以改变流程。
(4) ThrowsAdvice:异常处理通知
类全名:org.springframework.aop.ThrowsAdvice
在方法抛出异常后,做处理。
当该通知处理完异常后,会简单地将异常再次抛出给目标调用方法。
(5)自定义的通知,
Advisor:
将Pointcut与Advice结合到一起。
2、配置过程:
(1)配置目标对象
(2)配置通知
(3)利用ProxyFactoryBean将通知织入到目标对象,形成一个动态代理对象
(4)客户端使用动态代理来访问目标对象的方法。
在默认情况下,通知会应用到所有的方法之上。
Pointcut:
根据方法和类决定在什么地方织入通知
Advisor:
将Pointcut与Advice结合到一起。
自定义切入点:
步骤:
1)实现org.springframework.aop.ClassFilter
2)实现org.springframework.aop.MethodMatcher
3)实现org.springframework.aop.Pointcut
4)实现org.springframework.aop.PointcutAdvisor
注意:
在此可定义
private Advice advice;
private Pointcut pointcut;
在配置文件中,将自定义的切入点与通知绑订到一起
5)利用ProxyFactoryBean将advisor织入到目标对象
ProxyFactoryBean的作用:
依照配置信息,将切面应用到目标对象,生成动态代理对象。
(1) Spring只支持方法连接点,不支持属性连接点。
(原因是Spring AOP采用的是动态代理模式,而动态代理本身就是在方法调用前加入代码。)
(2) Spring只在运行时,将切面织入到目标对象。
(有些AOP实现,可以在编译是织入切面到目标对象。)
Injecting Advice(con’t d)
<bean id=”registerService’ class=”org.springframework.aop.framework.ProxyFactoryBean”>
<property name=”proxyInterfaces”> ←目标对象实现的接口
(如果没有定义接口,则所有方法使用CGLib
<value>aop.RegisterService</value>
</property>
<property name=”target”> ←目标对象
<ref local=”registerServiceTarget”/>
</property>
<property name=”interceptorNames”> ←需要织入到目标对象的切面
<list>
<value>logAdvice</value>
<value>throwsAdvice</value>
</list>
</property>
</bean>
五、切入点(Pointcut)
1、Pointcut<interface>
切入点是指通知/切面可以应用到哪些类,哪些方法之上。
Pointcut API
Pointcut:org.springframework.aop.Pointcut
对某些类某些方法应用切面。
Classfilter:org.springframework.aop.ClassFilter
用来过滤类(哪些类可以应用切面)
MethodMather:org.s