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

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

  • JDK动态代理

    它有两个重要的伙伴

  • Proxy:Proxy是所有动态代理的父类,它提供了一个静态方法来创建动态代理的class对象和实例
  • InvocationHandler:每个动态代理实例都有一个关联的InvocationHandler。在代理实例上调用方法时,方法调用将被转发到InvocationHandler的invoke方法

接口及实现类

public interface UserService {

    void addUser(String userName);
}

public class UserServiceImpl implements UserService {

    @Override
    public void addUser(String userName) {
        System.out.println("接收到user姓名" + userName);
    }
}

代理类

public class UserServiceInterceptor implements InvocationHandler {

        private Object realObject;

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("方法运行前");
            if (args != null && args.length > 0) {
                String str = (String) args[0];
                if ("aa".equals(str)) {
                    throw new RuntimeException("格式错误");
                }
            }
            Object invoke = method.invoke(realObject, args);
            System.out.println("方法运行结束");
            return invoke;
        }

    public Object getRealObject() {
        return realObject;
    }

    public void setRealObject(Object realObject) {
        this.realObject = realObject;
    }

    public UserServiceInterceptor(Object realObject) {
        this.realObject = realObject;
    }
}

运行类

public class UserMain {

    public static void main(String[] args) {
        UserService us = new UserServiceImpl();
        String userName = "张强";
        UserServiceInterceptor usi = new UserServiceInterceptor(us);
        UserService userProxy = (UserService) Proxy.newProxyInstance(us.getClass().getClassLoader(), us.getClass().getInterfaces(), usi);
        userProxy.addUser(userName);
    }
}

 

  • CGLIB代理

也有两个重要的东西

  • Enhancer:指定要代理的目标对象、实际处理代理逻辑的对象,最终调用create()方法得到代理对象,对这个对象的非final方法的调用都会发送给MethodInterceptor。
  • MethodInterceptor:动态代理对象的方法调用都会发送给intercept方法进行增强。

被代理类

public class UserServiceImpl {

    public void addUser(String userName) {
        System.out.println("接收到user姓名" + userName);
    }
}

代理类

public class UserServiceInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("方法运行前");
        if (args != null && args.length > 0) {
            String str = (String) args[0];
            if ("aa".equals(str)) {
                throw new RuntimeException("格式错误");
            }
        }
        Object invoke = methodProxy.invokeSuper(o, args);
        System.out.println("方法运行结束");
        return invoke;
    }
}

运行类

public class UserMain {

    public static void main(String[] args) {
        String userName = "张强";

        Enhancer enhancer = new Enhancer();
        enhancer.setCallback(new UserServiceInterceptor());
        enhancer.setSuperclass(UserServiceImpl.class);
        UserServiceImpl userServiceProxy = (UserServiceImpl) enhancer.create();
        userServiceProxy.addUser(userName);
    }
}

 

  • 总结
  • jdk动态代理是Java原生支持,不需要外部依赖,但是它只能基于接口进行代理。
  • CGLIB通过继承的方式进行代理,无论目标有没有实现接口都可以代理,但是无法处理final的情况。
  • CGLib所创建的动态代理对象在实际运行时候的性能要比JDK动态代理高不少,是CGLib在创建对象的时候所花费的时间却比JDK动态代理要多很多。因此,对于singleton的代理对象或者具有实例池的代理,因为无需频繁的创建代理对象,所以比较适合采用CGLib动态代理,反正,则比较适用JDK动态代理。

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值