第十八章 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,可以是任何一个类类加载器
-
图解
-
编码
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创建动态代理的原理: 父子继承关系创建代理对象,原始类作为父类,代理类作为子类,这样既可以保证两者方法一致,同时也可以在代理类中提供新的实现
-
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工厂如何加工原始对象成为代理对象
-
思路分析
-
编码
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"/>