标签: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中的反射机制和注解,就能随心所欲,只为代理类中特定方法进行代理。
标签:height 关联关系 特定 代码重复 aspect 代码 system and jdk
原文地址:https://www.cnblogs.com/hurro/p/12864060.html