Loading

第十八章 AOP底层实现原理

1.核心问题

1. AOP如何创建动态代理类
2. Spring工厂如何加工创建代理对象 
	通过原始对象的id值,获得的是代理对象

2.动态代理类的创建

2.1 JDK动态代理

通过方法Proxy.newProxyInstance(ClassLoader,interfaces,InvocationHandler)创建代理对象

返回值: 动态代理对象
  • InvocationHandler

    将额外功能写在InvocationHandler接口的invoke方法中,额外功能可以执行在原始方法执行之前\之后\前后\抛出异常
    
    Object invoke(Object proxy,Method method,Object[] args)
    
    返回值: 原始方法的返回值
    
    参数: proxy  -->代表代理对象,将Proxy.newProxyInstance创建好的代理对象传入invoke方法,现在基本不用,可以忽略
         method  -->额外功能所增加给的那个原始方法
         args  -->原始方法的参数
         
    原始方法的运行: method.invoke(userService,args),将运行结果作为原始方法的返回值返回
    
  • interfaces

    原始对象实现的接口
    作用: 代理类和原始类实现相同接口
    
    userService.getClass().getInterfaces()
    
  • ClassLoader

    类加载器的作用: 
    
    1. 通过类加载器将对应类的字节码文件加载进JVM
    2. 通过类加载器创建类的Class对象,进而创建这个类的对象
    
    过程: 编写User.java文件,编译为User.class文件,由类加载器将User.class文件加载进JVM,再由类加载器创建类的Class对象,才能创建这个类的对象
    
    获取类加载器: JVM为每一个类的.class文件,自动分配与之对应的ClassLoader
    
    在动态代理类的开发中,需要动态代理类,才能创建代理对象,但是,动态代理类是由动态字节码技术,也就是Proxy.newProxyInstance(interfaces,InvocationHandler),将创建的字节码直接写入JVM,没有.java文件,也没有.class文件,所以JVM不能给动态代理类分配ClassLoader,没有ClassLoader就无法创建类的Class对象,也就没办法创建类的对象,所以Proxy.newProxyInstance方法需要第三个参数,那就是类加载器
    
    解决办法: 借用一个ClassLoader,可以是任何一个类类加载器
    
  • 图解

    image

  • 编码

    public class TestJDKProxy {
        public static void main(String[] args) {
            //1.创建原始对象
            UserService userService = new UserServiceImpl();
            //2.JDK创建动态代理
            //以内部类的方式实现InvocationHandler接口
            InvocationHandler handler = new InvocationHandler() {
    
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //额外方法
                    System.out.println("----proxy log------");
    
                    //原始方法运行
                    Object ret = method.invoke(userService, args);
                    return ret;
                }
            };
            UserService userServiceProxy = (UserService) Proxy.newProxyInstance(TestJDKProxy.class.getClassLoader(), userService.getClass().getInterfaces(), handler);
            userServiceProxy.register(new User());
            userServiceProxy.login("rad","123");
        }
    }
    

2.2 CGlib的动态代理

CGlib创建动态代理的原理: 父子继承关系创建代理对象,原始类作为父类,代理类作为子类,这样既可以保证两者方法一致,同时也可以在代理类中提供新的实现

image

  • CGlib编码

    public class TestCGlib {
        public static void main(String[] args) {
            //1.创建原始对象
            UserService userService = new UserService();
            /*
                2.通过CGlib的方式创建动态代理对象
                和JDK创建动态代理高度一致,将实现接口变成继承父类
                Proxy.newProxyInstance(ClassLoader,interfaces,InvocationHandler)
    
                Enhancer.setClassLoader()
                Enhancer.setSuperClass()
                Enhancer.setCallback()  -->需要实现MethodInterceptor -->实现intercept方法(和invoke方法一致)
                enhancer.create()  --> 创建代理对象
    
             */
            Enhancer enhancer = new Enhancer();
            enhancer.setClassLoader(TestCGlib.class.getClassLoader());
            enhancer.setSuperclass(userService.getClass());
    
            MethodInterceptor interceptor = new MethodInterceptor(){
    
                @Override
                public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                    System.out.println("----log----");
                    Object ret = method.invoke(userService,args);
                    return ret;
                }
            };
    
            enhancer.setCallback(interceptor);
            UserService serviceProxy = (UserService) enhancer.create();
            serviceProxy.login("args","333");
            serviceProxy.register(new User());
        }
    }
    
  • 总结

    1. JDK创建代理对象 Proxy.newProxyInstance 通过接口实现来创建代理类
    2. CGlib创建动态代理 enhancer             通过继承父类来创建代理类
    

3.Spring工厂如何加工原始对象成为代理对象

  • 思路分析

    image

  • 编码

    public class ProxyBeanPostProcessor implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
            InvocationHandler handler = new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
                    System.out.println("-----new log-----");
                    Object ret = method.invoke(bean, args);
                    return ret;
                }
            };
            return Proxy.newProxyInstance(ProxyBeanPostProcessor.class.getClassLoader(),bean.getClass().getInterfaces(),handler);
        }
    }
    
    <bean id="proxyBeanPostProcessor" class="com.dong.factory.ProxyBeanPostProcessor"/>
    
posted @ 2022-07-24 15:48  苏无及  阅读(43)  评论(0编辑  收藏  举报