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);
}
}
Original: https://www.cnblogs.com/suwuji/p/16514628.html
Author: 苏无及
Title: 第十八章 AOP底层实现原理
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/612590/
转载文章受原作者版权保护。转载请注明原作者出处!