动态代理(设计模式)
代理模式概述
代理模式属于结构型模式,指的是为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式包含角色及其职责:
- 抽象角色[Subject]:通过接口或抽象类声明真实角色待实现方法;
- 代理角色[Proxy]:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作(可做增强操作);
- 真实角色[RealSubject]:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用;
- 代理模式有不同的形式,主要有两种,静态代理、动态代理(静态代理较简单不做介绍)
- 动态代理分为两种:
- jdk 动态代理,基于接口;
- cglib 代理,基于类; 可以在内存中动态的创建对象,而不需要实现接口。
代理模式包含角色及其职责:
设计原则:
- 隔离原则
在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到桥梁的作用, 其特征是代理类与委托类有同样的接口。
- 开闭原则
代理类不仅仅是一个隔离客户端和委托类的中介。我们还可以借助代理来在增加一些功能,而不需要修改原有代码,严重的符合开闭原则。
代理模式的优点:
- 公共业务交给代理角色,实现业务的分工。公共业务发生扩展的时无需修改源码,符合开闭原则,系统具有较好的灵活性和可扩展性;
- 能够协调调用者和被调用者,在一定程度上降低了系统的耦合度;
源码演示:
第一个:jdk动态代理
1、定义接口类
package com.northeasttycoon.proxy.dynamic.proxy; /** * @author :tycoon * @date :2018-10-01 9:08 */ public interface IUserDao { void findUserPojo(); }
2、实现接口类
package com.northeasttycoon.proxy.dynamic.proxy; /** * @author :tycoon * @date :2018-10-01 9:08 */ public class UserImpl implements IUserDao { @Override public void findUserPojo() { System.out.println("此方法为jdk动态代理。查询用户信息为:{userID:1001,userName:Northeast Tycoon,alias:Java.Zhao}"); } }
3、jdk动态代理实现类
package com.northeasttycoon.proxy.dynamic.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * @author :tycoon * @date :2018-10-01 9:07 */ public class ProxyInvocationHandler implements InvocationHandler { // 需要代理的对象,既:真实对象 private Object target; public void setObject(Object target) { this.target = target; } public Object getProxy() { return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } /* * 处理代理对象的方法时会调用此方法 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(); // 通过反射实现动态代理,调用真实对象方法 Object result = method.invoke(target, args); after(); return result; } // 执行前-增强方法 public void before() { System.out.println(" This is northeasttycoon jdkDynamicProxy,调用动态代理方法前------"); } // 执行后-增强方法 public void after() { System.out.println("This is northeasttycoon jdkDynamicProxy,调用动态代理方法后------"); } }
第二个:cglib 动态代理
1、定义目标对象(真实对象)
package com.northeasttycoon.proxy.dynamic.proxy; /** * @author :tycoon * @date :2018-10-01 9:10 */ public class UserDao { public void findUserPojo() { System.out.println("此方法为CGlib动态代理。查询用户信息为:{userID:1001,userName:Northeast Tycoon,alias:Java.Zhao}"); } }
2、cglib 动态代理类
package com.northeasttycoon.proxy.dynamic.proxy; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * @author :tycoon * @date :2018-10-01 9:28 */ public class CglibDynamicProxy implements MethodInterceptor { //维护一个目标对象 private Object target; //构造器,传入一个被代理的对象 public CglibDynamicProxy(Object target) { this.target = target; } //返回一个代理对象: 是 target 对象的代理对象 public Object getProxyInstance() { //1. 通过CGLIB动态代理获取代理对象的过程 Enhancer enhancer = new Enhancer(); //2. 设置enhancer对象的父类 enhancer.setSuperclass(target.getClass()); //3. 设置enhancer的回调对象 enhancer.setCallback(this); //4. 创建子类对象,即代理对象 return enhancer.create(); } /** * 重写 intercept 方法,会调用目标对象的方法 * @param arg0 cglib生成的代理对象 * @param method 被代理对象的方法 * @param args 传入方法的参数 * @param arg3 代理的方法 * @return 对象 * @throws Throwable */ @Override public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable { System.out.println("cglib代理模式 ~~ start"); Object returnVal = method.invoke(target, args); System.out.println("cglib代理模式 ~~ end"); return returnVal; } }
测试类
package com.northeasttycoon.proxy.dynamic.proxy; import org.junit.jupiter.api.Test; /** * @author :tycoon * @date :2018-10-01 9:18 */ public class TestProxy { /** * jdk 动态代理实现 */ @Test public void test01(){ //需要被代理的对象 UserImpl userService = new UserImpl(); //生成代理类 ProxyInvocationHandler pih = new ProxyInvocationHandler(); pih.setObject(userService); IUserDao proxy = (IUserDao) pih.getProxy(); //调用代理类的方法 proxy.findUserPojo(); } /** * cglib的动态代理 */ @Test public void test02(){ //创建目标对象 UserDao target = new UserDao(); //获取到代理对象,并且将目标对象传递给代理对象 UserDao proxyInstance = (UserDao)new CglibDynamicProxy(target).getProxyInstance(); //执行代理对象的方法,触发intecept 方法,实现对目标对象的调用 proxyInstance.findUserPojo(); } }
测试结果: