欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

动态代理的几种实现方式及优缺点

程序员文章站 2022-06-17 19:53:18
...

动态代理:是使用反射和字节码,在运行期间创建指定接口或类的子类以及它的实例对象的一项技术,通过这个技术可以对代码进行无侵入式的增强。

源文件生成实例对象的过程如下:

动态代理的几种实现方式及优缺点
关于动态代理的底层原理,在另一篇文章中已经介绍过了。 你必须要学会的动态代理

java的动态代理技术的实现主要有两种方式:

  • JDK原生动态代理
  • CGLIB动态代理

JDK原生动态代理:

使用到一个类Proxy和一个接口InvocationHandler。Proxy是所有动态类的父类,它提供一个静态方法来创建动态代理的class对象和实例,这个方法就是newProxyInstance(),

InvocationHandler:每个动态代理实例都有一个相关联的InvocationHandler方法,在代理实例调用时,方法调用将被转发到InvocationHandler的invole方法。

代码实验:

User类有两个属性,name和age,代码省略

UserService:

public interface UserService {
    public void addUser(User user);
}

UserServiceImpl:

public class UserServiceImpl implements UserService {
    @Override
    public void addUser(User user) {
        System.out.println("新增用户成功,数据为:"+user.toString());
    }
}

UserServiceProxy:实现InvocationHandler,重写invoke方法,做前置增强,判断用户年龄是否大于0,如果小于等于0就报运行时异常

public class UserServiceProxy implements InvocationHandler {

    private Object realObj;
    private static Logger logger = Logger.getLogger(UserServiceProxy.class.getName());

    public Object getRealObj() {
        return realObj;
    }

    public void setRealObj(Object realObj) {
        this.realObj = realObj;
    }

    public UserServiceProxy(Object realObj) {
        super();
        this.realObj = realObj;
    }

    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        if(objects!=null && objects.length>0 && objects[0] instanceof User){
            User user = (User)objects[0];
            if(user.getAge()<=0){
                throw new RuntimeException("用户年龄不符合");
            }
        }
        Object ret = method.invoke(realObj,objects);
        logger.info("数据添加成功");
        return ret;
    }
}

Client:

public class Client {
    public static void main(String[] args) {
        User user  =new User();
        user.setName("张三");
        user.setAge(0);
        UserService us = new UserServiceImpl();
        UserServiceProxy usp = new UserServiceProxy(us);
        UserService proxy = (UserService) Proxy.newProxyInstance(us.getClass().getClassLoader(),us.getClass().getInterfaces(),usp);
        proxy.addUser(user);
    }
}

运行结果:

Exception in thread "main" java.lang.RuntimeException: 用户年龄不符合
	at DynamicProxy.JDK.UserServiceProxy.invoke(UserServiceProxy.java:30)
	at com.sun.proxy.$Proxy0.addUser(Unknown Source)
	at DynamicProxy.JDK.Client.main(Client.java:13)

看来过滤起了作用。将年龄改为大于0的数时,能够正常运行。

CGLIB动态代理

CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,允许我们在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理:

  • Enhancer:来指定要代理的目标对象,实际处理代理逻辑的对象,最终通过调用create()方法得到代理对象,对这个对象的所有非final方法的调用都会转发给MethodInterceptor;
  • MethodInterceptor:动态代理对象的方法调用丢回转发到intercept方法进行增强

UserServiceImpl类:无需接口

public class UserServiceImpl {

    public void addUser(User user) {
        System.out.println("新增用户成功,数据为:"+user.toString());
    }
}

UserServiceProxy:逻辑几乎一样

public class UserServiceProxy implements MethodInterceptor {

    private static Logger logger = Logger.getLogger(UserServiceProxy.class.getName());

    public Object intercept(Object o, Method method, Object[] objects,MethodProxy proxy) throws Throwable {
        if(objects!=null && objects.length>0 && objects[0] instanceof User){
            User user = (User)objects[0];
            if(user.getAge()<=0){
                throw new RuntimeException("用户年龄不符合");
            }
        }
        Object ret = proxy.invokeSuper(realObj,objects);
        logger.info("数据添加成功");
        return ret;
    }
}

Client

public class Client {
    public static void main(String[] args) {
        User user  =new User();
        user.setName("张三");
        user.setAge(0);
        Enhancer enhancer = new EnHancer();
        enhancer.setSuperClass(UserServiceImpl.class);
        enhancer.setCallback(new UserServiceProxy());
        UserServiceImpl usi = (UserServiceImpl) enhancer.create();
        usi.addUser(user);
    }
}

总结:

  • JDK原生动态代理是Java原生支持的,不需要任何外部依赖,但是它只能基于接口进行代理(需要代理的对象必须实现于某个接口)
  • CGLIB通过继承的方式进行代理(让需要代理的类成为Enhancer的父类),无论目标对象有没有实现接口都可以代理,但是无法处理final的情况。
相关标签: 设计模式