码迷,mamicode.com
首页 > 其他好文 > 详细

简单jdk动态代理

时间:2020-05-16 17:06:06      阅读:58      评论:0      收藏:0      [点我收藏+]

标签:height   关联关系   特定   代码重复   aspect   代码   system   and   jdk   

在学习动态代理之前,最好先去理解静态代理,如果未曾了解过静态代理,建议先理解静态代理。

在静态代理中,你需要自己去写一个代理类和被代理类实现相同的接口,在代理类中写上代理逻辑,确定要代理哪些方法,如果有新的变动需要修改源代码,重新编译部署,非常不方便,可以看看下面的例子:

我们已经通过静态代理的方实现了再登陆之前打印日志的能,但是现在有新的需求,A1类除了登陆,还要实现吃饭的功能,吃饭前后也要打印日志,

技术图片

为了实现功能,于是做了一些修改,下图中红色的部分就是改动的部分:

技术图片

 

  

至此,静态代理的缺点十分明显了,因为代理类是在编译之前就写好的,而且代理类和被代理类关系太紧,只要被代理类的逻辑变了,或者实现的接口变了,代理也得跟着变,直接修程序原意味着要重新测试,部署,难以维护;问题之二:代理中的重复代码(打印日志部分)是无法通过纵向抽取(继承)来消除的,也就有了横向抽取(横切)来解决,于是就AOP(Aspect Oriented Progranming),那又是另外一个故事了。

试想,如果在编译之前不能用确定代理类是哪一种类型,只有在编译的时候根据传入接口,代理逻辑,需要代理的类来生成代理类,不用我们自己写代理类,也就没有代码重复和大面积修改的行为,这就是jdk的动态代理机制,整体架构如下.                                   

技术图片

tip :    1)依赖关系:A类的某个方法的入参是B类对象,这是一种临时的关系          2)关联关系:A类的成员变量中包含B类对象

通过上面这种组织关系,调用者只需要面对JDK自动生成的代理类,代理类会去完成业具体的业务逻辑和代理逻辑,不用我们自己编写代理类,自然也就不会为接口改变而犯难了。想要使用jdk的动态代理,首先被代理类你的写出来,然后你要解决代理逻辑写在那个类的问题。

为了解决第一个问题:需要下面两个类:

//JDK动态代理只能代理有接口的类,所以和静态代理一样,需要有接口,和对应的实现类
public interface UserService { void login(String userName,String password); void register(); }

/**
 * 被代理的对象  也是接口的实现类
*/
public class UserServiceImpl implements UserService,UserLife{

@Override

public void login(String userName, String password) {

System.out.println(userName + " login");

}

@Override
public void register() {
System.out.println("register().....");
}
}

 第二步 :代理逻辑写在什么地方,按照jdk动态代理的实现规则,代理逻辑要写在一个实现 了 java.lang.reflect.InvocationHandler接口的类中,于是就有了下面的代码

public class UserServiceInvocationHandler implements InvocationHandler {

    /**
     * 要被代理的目标对象
     */
    private UserService userService;

    public UserServiceInvocationHandler(UserService userService){
        this.userService = userService;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("do something before 打印日志....");
       //调用被代理对象的业务处理方法
        Object result = method.invoke(userService,args);
        System.out.println("do something before 打印日志....");
        return result;
    }
}

 至此,我们要写的代码已经写完了,动态代理类是在运行的时候动态生成的,该如何去调用者动态生成的对象去完成特定功能呢?具体代码如下

public class Test{

    public static void main(String[] args) {
        System.out.println("---------动态代理类-----------");
//让jvm动态生成代理类 这就是JDK的动态代理 UserService service = (UserService)Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[]{UserService.class, UserLife.class},//被代理类实现的接口 new UserServiceInvocationHandler(new UserServiceImpl()));//代理逻辑 service.login("jack","12345"); System.out.println("-----------------------"); service.register(); System.out.println("动态代理类的名字" + service.getClass().getName()); } }

------------------------------运行结果如下--------------------------

---------动态代理类-----------
do something before 打印日志....
jack login
do something before 打印日志....
-----------------------
do something before 打印日志....
register().....
do something before 打印日志....
动态代理类的名字com.sun.proxy.$Proxy0


 


总结和思考:通过JDK的动态代理机制,我们可以对增强类的功能,在那些需要的方法执行前后加入相应的代理逻辑,但是本文演示的只是最简单的动态代理方式,也就是默认代理类中的所有方法的都需要被代理,所以被代理的类的每一个方法调用前后都会执行额外操作,如果想要灵活的使用动态代理还需要借助java中的反射机制和注解,就能随心所欲,只为代理类中特定方法进行代理。 

 

简单jdk动态代理

标签:height   关联关系   特定   代码重复   aspect   代码   system   and   jdk   

原文地址:https://www.cnblogs.com/hurro/p/12864060.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!