1 什么是AOP:
AOP AspectOrientedPrograming面向切面编程
AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)
Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码
AspecJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,
AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入
2 AOP底层原理;
就是代理机制:
*动态代理:(JDK中使用)
- * JDK的动态代理,对实现了接口的类生成代理.
3 Spring的AOP代理:
JDK动态代理:对实现了接口的类生成代理
CGLib代理机制:对类生成代理
4 AOP的术语:
Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点.
Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义.
Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下,Introduction可以在运行期为类动态地添加一些方法或Field.
Target(目标对象):代理的目标对象
Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程.
Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类
Aspect(切面):是切入点和通知(引介)的结合
spring采用动态代理织入,而AspectJ采用编译期织入和类装在期织入
对于不使用接口的业务类,无法使用JDK动态代理
CGlib采用非常底层字节码技术,可以为一个类创建子类,解决无接口代理问题
5 AOP的底层实现:
5.1 JDK动态代理
JDK1.3引入动态代理技术
编写动态代理程序
java.lang.reflect.Proxy
java.lang.reflect.InvocationHandler
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @Title: JDK的动态代理的机制
* @ClassName:JDKProxy.java
* @Description:
*
* @Copyright2016-2017 Powered By 研发中心
* @author: 王延飞
* @date:2016年9月19日 下午10:28:08
* @version V1.0
*/
publicclassJDKProxyimplementsInvocationHandler[]{
privateUserDao userDao;
publicJDKProxy(UserDao userDao){
super();
this.userDao = userDao;
}
publicUserDao createProxy(){
UserDao proxy =(UserDao)Proxy.newProxyInstance(userDao.getClass()
.getClassLoader(), userDao.getClass().getInterfaces(),this);
return proxy;
}
// 调用目标对象的任何一个方法 都相当于调用invoke();
publicObject invoke(Object proxy,Method method,Object[] args)
throwsThrowable{
if("add".equals(method.getName())){
// 记录日志:
System.out.println("日志记录=================");
Object result = method.invoke(userDao, args);
returnresult;
}
return method.invoke(userDao, args);
}
}
5.2 CGLIB动态代理
对于不使用接口的业务类,无法使用JDK动态代理
CGlib采用非常底层字节码技术,可以为一个类创建子类,解决无接口代理问题
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
/**
* 使用CGLib生成代理对象
*
*/
publicclassCGLibProxyimplementsMethodInterceptor{
privateProductDao productDao;
publicCGLibProxy(ProductDao productDao){
super();
this.productDao = productDao;
}
publicProductDao createProxy(){
// 使用CGLIB生成代理:
// 1.创建核心类:
Enhancerenhancer=newEnhancer();
// 2.为其设置父类:
enhancer.setSuperclass(productDao.getClass());
// 3.设置回调:(相当于JDK动态代理中的回调)
enhancer.setCallback(this);
// 4.创建代理:
return(ProductDao) enhancer.create();
}
- /** * @param proxy CGlib根据指定父类生成的代理对象 * @param method 拦截的方法 * @param args 拦截方法的参数数组 * @param methodProxy 方法的代理对象,用于执行父类的方法 * @return */
publicObject intercept(Object proxy,Method method,Object[] args,
MethodProxy methodProxy)throwsThrowable{
if("add".equals(method.getName())){
System.out.println("日志记录==============");
// 放行代码:这里相当于JDK中的(method.invoke)
Object obj = methodProxy.invokeSuper(proxy, args);
return obj;
}
return methodProxy.invokeSuper(proxy, args);
}
}
5.3 代理总结
Spring在运行期,生成动态代理对象,不需要特殊的编译器
Spring AOP的底层就是通过JDK动态代理或CGLib动态代理技术为目标Bean执行横向织入
- 1.若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理。
- 2.若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。
程序中应优先对接口创建代理,便于程序解耦维护
标记为final的方法,不能被代理,因为无法进行覆盖
- JDK动态代理,是针对接口生成子类,接口中方法不能使用final修饰
- CGLib是针对目标类生产子类,因此类或方法不能使final的
Spring只支持方法连接点,不提供属性连接