概念:AOP (Aspect Oriented Programing) ⾯向切⾯编程 。是以切⾯为基本单位的程序开发,通过切⾯间的彼此协同,相互调⽤,完成程序的构建。(本质即spring动态代理开发,通过代理类为原始类增加功能)(切⾯ = 切⼊点 + 额外功能)。
AOP底层实现原理
动态代理类的创建
1:jdk的动态代理(原始类和代理类实现相同的接口)
jdk的动态代理使用Proxy的newProxyInstance方法来创建代理类:
代码模拟实现:
原始类这里就不进行展示,包括一个out方法,参数是一个字符串,功能是输出这个参数
package JDK;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKTest {
public static void main(String[] args) {
//原始对象
ProductService productService = new ProductServiceimpl();
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//运行原始方法,得到原始方法的返回值,productService为原始类,args即原始方法参数
Object yuanshiBeen = method.invoke(productService,args);
//设置额外功能,这里为了方便输出一句话
//根据需要添加在原始方法运行前或运行后
System.out.println("增加额外功能");
return yuanshiBeen;
}
};
ProductService productServiceProxy = (ProductService) Proxy.newProxyInstance(ProductServiceimpl.class.getClassLoader(), productService.getClass().getInterfaces(),invocationHandler);
productServiceProxy.out("张三");
}
}
额外功能成功被增加进去了
为什么需要借用一个类加载器?
2:CGlib的动态代理(父子继承关系创建代理对象,原始类作为父类,代理类作为子类)
通过代理类对原始类方法的重写达到:
1:代理类和原始类方法一致
2:代理类提供新的额外功能
的效果。
模拟实现:
package CGlib;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class TestCJlib {
public static void main(String[] args) {
ProductService2 productService2 = new ProductService2();
Enhancer enhancer = new Enhancer();
//借用类加载器
enhancer.setClassLoader(TestCJlib.class.getClassLoader());
//得到父类的class对象
enhancer.setSuperclass(productService2.getClass());
MethodInterceptor methodInterceptor = new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//增添额外功能
System.out.println("这是额外功能");
//调用原始对象,并记录其返回值
Object o2 = method.invoke(productService2,objects);
return o2;
}
};
enhancer.setCallback(methodInterceptor);
//获得代理类对象
ProductService2 productService21 = (ProductService2) enhancer.create();
productService21.out("卫龙大面筋");
}
}
jdk动态代理和CGlib动态代理的区别
- JDK代理只能对实现接口的类生成代理;CGLib是针对类实现代理,对指定的类生成一个子类,并覆盖其中的方法,这种通过继承类的实现方式,不能代理final修饰的类。
- JDK代理使用的是反射机制实现aop的动态代理,CGLib代理使用字节码处理框架ASM,通过修改字节码生成子类。在jdk6、jdk7、jdk8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLIB代理效率,只有当进行大量调用的时候,jdk6和jdk7比CGLIB代理效率低一点,但是到jdk8的时候,jdk代理效率高于CGLIB代理,总之,每一次jdk版本升级,jdk代理效率都得到提升,而CGLIB代理消息确有点跟不上步伐。
- JDK动态代理机制是委托机制,具体说动态实现接口类,在动态生成的实现类里面委托hanlder去调用原始实现类方法,CGLib则使用的继承机制,具体说被代理类和代理类是继承关系,所以代理类是可以赋值给被代理类的,如果被代理类有接口,那么代理类也可以赋值给接口。
- spring默认使用jdk代理,当没有实现接口或者在配置文件中进行设置后使用CGlib代理
spring如何在二者之间选择?
1、当Bean实现接口时,Spring就会用JDK的动态代理。
2、当Bean没有实现接口时,Spring使用CGlib是实现。
3、可以强制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)。
spring加工原始类的方式(为什么我们通过原始类id拿到的是代理类)
spring对原始类的加工借助了spring工厂中对工厂所创建的对象进行加工时使用的BeenPostProcessor接口:
底层通过实现BeanPostProcessor接口进而实现其postProcessBeforeInitialization方法(一般不做处理,直接返回对象即可)和postProcessAfterInitialization方法(调用之前提到的代理的底层方法并返回创建出来的代理对象)。即通过BeanPostProcessor插入进原始类对象的创建过程中,在其中通过动态代理创建出代理类对象,并返回这个对象,这样,我们通过原始类id创建的对象就是代理类对象。
模拟实现:
原始类只有一个方法就是输出参数里的字符串,这里使用jdk代理,所以需要实现一个接口,这里就不进行展示
package springProcess;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//模拟spring底层加工原始类
public class SpringProcess implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//这个方法一般不进行操作,但要记得返回参数里的原始类
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//BeanPostProcessor针对所有对象,所以这里加一个选择机制
if(bean instanceof nameService) {
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("这是额外功能");
Object ret = method.invoke(bean, args);
return ret;
}
};
nameService nameService = (springProcess.nameService) Proxy.newProxyInstance(SpringProcess.class.getClassLoader(), bean.getClass().getInterfaces(), invocationHandler);
return nameService;
}
return bean;
}
}
配置文件:
<bean id="nameservice" class="springProcess.nameServiceImpl"/>
<bean id="process" class="springProcess.SpringProcess"/>