CGlib动态代理和jdk动态代理相关(底层实现,区别,AOP实现过程)

概念: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"/>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值