Java Spring-AOP CGlib和JDK动态代理实现
编码是为了解决生活中的问题,譬如现在我想用筷子吃饭的时候看手机,那么首先会有两个对象。
现在如果是面向对象编程思想,我们会new一个筷子对象,new一个手机对象,然后先调用 chopsticks.pickUp() ,再调用 phone.user() 。
那有没有一种做法,在不改动现有两个对象类内容的情况下,我直接把手机的使用方法增强到筷子的拿起方法里,这样我直接调用这个增强后的操作就能完成吃饭的时候玩手机这个功能,这个就是AOP的思想,即面向切面编程。
AOP:Aspect Oriented Programming,面向切面编程,将创建Bean的权利给第三方,第三方创建的Bean是代理Bean的代理类,代理增强的方法和Bean本身的方法当作一个切面,是对面向对象编程OOP的升华。OOP是纵向对一个事物的抽象,一个对象包括静态的属性信息,包括动态的方法信息等。而AOP是横向的对不同事物的抽象,属性与属性、方法与方法、对象与对象都可以组成一个切面,而用这种思维去设计编程的方式叫做面向切面编程。
根据这个例子,再介绍几个AOP的术语:
此时use()方法的代码逻辑叫做通知,通知有5种类型。
那么实现此操作,有两种实现方式,一种是JdkDynamicAopProxy实现,一种是CglibAopProxy实现。
JdkDynamicAopProxy源码获取代理对象:
CglibAopProxy源码获取代理对象:
从源码中我们可以看出来区别:
JDK动态代理:基于接口动态生成实现类的代理对象,目标类有接口Cglib动态代理:基于被代理对象动态生成子对象为代理对象,目标类无接口且不能使用final修饰
一般如果目标有接口的话,Spring默认使用JDK去动态代理实现,也可以配置指定使用Cglib实现。
下面简单的Demo介绍一下两种实现的基本原理:
JDK动态代理Demo:
//实现BeanPosrProcessor接口,实现Bean处理器的after方法将代理类封装成BeanDefinition对象注册到BeanDefinitionMap中//实现ApplicationContextAware接口,实现aware回调方法,获取Spring容器中的增强方法类public class AopBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {private ApplicationContext applicationContext;//目的:对Chopsticks中的pickUp()进行增强,增强的方法存在于Phonepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {//生成当前Bean的Proxy对象Object beanProxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(),bean.getClass().getInterfaces(), new InvocationHandler() {public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//Phone的获取(从Spring容器中获取)Phone phone= applicationContext.getBean(Phone.class);//执行增强对象的方法,此处举例前置通知类型phone.use();//执行目标对象的目标方法Object result = method.invoke(bean, args);return result;}});return beanProxy;return bean;}public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {//获取Spring容器this.applicationContext = applicationContext;}}
Cglib实现Demo:
public class CGlibTest {public static void main(String[] args) {//CGlib基于父类(目标类)生成Proxy//目标对象Chopsticks chopsticks= new Chopsticks();//通知对象Phone phone= new Phone();//编写CGlib代码Enhancer enhancer = new Enhancer();//设置父类enhancer.setSuperclass(Chopsticks .class);//生成的代理对象就是Chopsticks的子类//设置回调enhancer.setCallback(new MethodInterceptor() {@Override//intercept方法相当于JDK的Proxy的invoke方法public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {//执行增强对象的方法,此处举例前置通知类型phone.use();Object invoke = method.invoke(target, objects);//执行目标方法return invoke;}});//生成代理对象Chopsticks o = (Chopsticks ) enhancer.create();//测试o.show();}}