java动态代理实现与原理详细分析
关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式–代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理。
代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。简单的说就是,我们在访问实际对象时,是通过代理对象来访问的,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。在后面我会
解释这种间接性带来的好处。代理模式结构图(图片来自《大话设计模式》):
看这个是不是有点费劲,来下面我们来个简单的
通过代理控制对象的访问,可以详细访问某个对象的方法,在这个方法调用处理,或调用后处理。既(AOP微实现) ,AOP核心技术面向切面编程。
代理模式运用场景
SpringAop ,事务原理,日志打印,权限控制,远程调用,安全代理
代理的分类
静态代理(静态定义代理类)
动态代理(动态生成代理类)
Jdk自带动态代理
Cglib 、javaassist(字节码操作库)
什么是静态代理
由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
package com.evan.springboot.designStudy.proxyDemo;
/**
* @author evanYang
* @version 1.0
* @date 2020/4/29 上午 10:42
*/
public interface UserService {
void save();
}
public class UserServiceImpl implements UserService {
@Override
public void save() {
System.out.println("插入用户成功");
}
}
package com.evan.springboot.designStudy.proxyDemo.st;
import com.evan.springboot.designStudy.proxyDemo.UserService;
import com.evan.springboot.designStudy.proxyDemo.UserServiceImpl;
/**
* @author evanYang
* @version 1.0
* @date 2020/4/29 上午 10:45
*/
public class UserProxy implements UserService {
private UserService userService;
public UserProxy(UserService userService){
this.userService=userService;
}
@Override
public void save() {
System.out.println("开启事务");
userService.save();
System.out.println("事务执行");
}
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
UserProxy userProxy = new UserProxy(userService);
userProxy.save();
}
}
什么是动态代理
1.代理对象,不需要实现接口
2.代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)
3.动态代理也叫做:JDK代理,接口代理
JDK动态代理
- 原理:
根据类加载器和接口创建代理类(此代理类是接口的实现类,所以必须使用接口,面向接口生成代理,位于java.lang.reflect包下)
- 实现方式
1,通过实现InvocationHandler接口创建自己的调用处理器UserJDkProxy。
- 通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});
- 通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
- 通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
缺点:jdk动态代理,必须是面向接口,目标业务类必须实现接口
package com.evan.springboot.designStudy.proxyDemo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @author evanYang
* @version 1.0
* @date 2020/4/29 上午 10:57
*/
public class UserJDkProxy implements InvocationHandler {
private UserService userService;
public UserJDkProxy(UserService userService){
this.userService=userService;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("jdk 动态代理开始");
Object invoke = method.invoke(userService, args);
System.out.println("Jdk 动态代理结束");
return invoke;
}
}
package com.evan.springboot.designStudy.proxyDemo;
import java.lang.reflect.Proxy;
/**
* @author evanYang
* @version 1.0
* @date 2020/4/29 上午 11:06
*/
public class Client {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
UserJDkProxy userJDkProxy = new UserJDkProxy(userService);
UserService o = (UserService) Proxy.newProxyInstance(userJDkProxy.getClass().getClassLoader(), userService.getClass().getInterfaces(), userJDkProxy);
o.save();
}
}
Cglib动态代理
- 原理:
利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
什么是CGLIB动态代理
使用cglib[Code Generation Library]实现动态代理,并不要求委托类必须实现接口,底层采用asm字节码生成框架生成代理类的字节码
package com.evan.springboot.designStudy.proxyDemo;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author evanYang
* @version 1.0
* @date 2020/4/29 上午 11:31
*/
public class UserCglibProxy implements MethodInterceptor {
private Object object;
public Object getInstance(Object object){
this.object=object;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(object.getClass());
enhancer.setCallback(this);
Object o = enhancer.create();
return o;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Cglib 动态代理事务开始");
Object invoke = methodProxy.invoke(object, objects);
System.out.println("Cglib 动态代理事务结束");
return invoke;
}
}
package com.evan.springboot.designStudy.proxyDemo;
import java.lang.reflect.Proxy;
/**
* @author evanYang
* @version 1.0
* @date 2020/4/29 上午 11:06
*/
public class Client {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
UserJDkProxy userJDkProxy = new UserJDkProxy(userService);
UserService o = (UserService) Proxy.newProxyInstance(userJDkProxy.getClass().getClassLoader(), userService.getClass().getInterfaces(), userJDkProxy);
o.save();
UserCglibProxy userCglibProxy = new UserCglibProxy();
UserService instance = (UserService) userCglibProxy.getInstance(userService);
instance.save();
}
}
CGlib动态代理和JDK动态代理的区别
java动态代理是利用反射机制生成一个实现代理接口的匿名内部类
cglib是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理
Spring中
1,如果目标对象实现了接口,默认情况下回采用JDK的动态代理实现AOP
2,如果目标对象实现了接口,可以强制使用CGlib实现AOP
3,如果目标没有实现接口,必须采用Cglib库,spring会自动在jdk动态代理和cglib之间转换
JDK动态代理只能对实现了接口的类型生成代理,而不能针对类
Cglib是针对类实现代理,主要是对指定类生成一个子类,覆盖其中方法。
因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态。
转载:https://blog.csdn.net/weixin_30409927/article/details/105838384