前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >Java动态代理

Java动态代理

作者头像
心平气和
发布2021-03-16 16:30:24
发布2021-03-16 16:30:24
44600
代码可运行
举报
运行总次数:0
代码可运行

一、什么是动态代理

打个比方,如果系统中有2个类,A和B,以前是A依赖B,即A直接调用B的某个方法,表示为A->B;

现在调用链路变成A->B->C,即A先调用B,B再调用C,不过B在调用C前后会加些逻辑,这时候B相当于一个代理人的角色,并且B的拦截是在程序运行过程中动态产生的,这种情况我们叫动态代理。

二、为什么需要动态代理

动态代理主要有以下几个作用:

1、提高系统的扩展性

像上面的情况,以前的调用链是A->B,现在要在B的基础上加些逻辑,如B是一个订单服务,这个B是的代码我们拿不到,只有Jar包,我们想在保存订单后发个邮件,当然我们可以在调用方去做,不过每个调用方都做这个事情,相同的逻辑就会分散在不同的地方,不便于后续的维护,这个时候就可以通过动态代理来增强系统的功能,并且不用修改B的代码。

2、精简代码,将逻辑收拢

这个什么意思呢,通过动态代理我们可以让使用者非常简单的使用,不用关注一些实现的细节,如Mybatis中只要写个接口,然后在Xml中写Sql语句,不用写如何读取Sql,怎么与JDBC打交道的代码,就可以轻松的访问数据库了。

其它还有Fein,也只要定义接口就可以了,如何执行Url请求,怎么解析响应的代码都不用我们写,让访问Rest服务变得非常简单。

三、Java中动态代理使用

主要有2种方式:

1、JDK代理

其代理对象必须实现接口InvocationHandler,它的实现方式是在运行期间创建一个接口的实现类来完成目标对象的代理。

使用步骤如下:

1)、实现InvocationHandler接口;

2)、调用Proxy.newProxyInstance生成代理对象

先实现接口InvocationHandler

代码语言:javascript
代码运行次数:0
复制
public class JDKProxy implements InvocationHandler{
    Object target;  //被代理的对象

    public JDKProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("JDKProxy before");
        Object result = method.invoke(target, args); 
        System.out.println("JDKProxy after");

        return result;
    }
 }

编写测试代码:

代码语言:javascript
代码运行次数:0
复制
public void testJDKProxy(){
        UserServiceImpl userServiceImpl = new UserServiceImpl();
        ClassLoader classLoader = userServiceImpl.getClass().getClassLoader();
        Class[] interfaces = userServiceImpl.getClass().getInterfaces();
        InvocationHandler logHandler = new JDKProxy(userServiceImpl);
        UserService proxy = (UserService) Proxy.newProxyInstance(classLoader, interfaces, logHandler);

        proxy.select();
}

UserServiceImpl代码如下:

代码语言:javascript
代码运行次数:0
复制
public class UserServiceImpl implements UserService {
    public void select() {
        System.out.println("select被调用");
    }

UserSerivice接口定义如下:

代码语言:javascript
代码运行次数:0
复制
public interface UserService {
    void select();
}

2、CGLIB代理

它的实现是通过ASM(开源的Java字节码编辑类库)操作字节码,性能比JDK代理的强。

使用步骤如下:

1)、实现接口MethodInterceptor

2)、生成Enhancer类实例,调用setCallback方法绑定代理对象

先实现接口MethodInterceptor

代码语言:javascript
代码运行次数:0
复制
public class CglibProxy implements MethodInterceptor{

    @Override
    public Object intercept(Object object, Method method, Object[] objects, net.sf.cglib.proxy.MethodProxy methodProxy){
        Object result=null;

        System.out.println("CglibProxy before");

        try {
            result = methodProxy.invokeSuper(object, objects);
        }catch (java.lang.Throwable ex){
            System.out.println(ex.getMessage());
        }
        System.out.println("CglibProxy after");

        return result;
    }
}

编写测试代码

代码语言:javascript
代码运行次数:0
复制
public void testCglibProxy(){
        CglibProxy proxy = new CglibProxy();
        Enhancer enhancer = new Enhancer();
        //设置超类,注意是接口不是实现类
        enhancer.setSuperclass(UserService.class);
        //绑定代理对象
        enhancer.setCallback(proxy);

        UserService dao = (UserService)enhancer.create();
        dao.update();
        dao.select();
    }
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-02-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员升级之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档