动态代理模式
什么是动态代理模式?
动态代理模式就是对不同的目标类,能通过一个代理类来完成指定的切入操作。而不需要针对新增的目标类重新设计代理类。
Java如何实现动态代理?
还是拿静态代理所用的例子
JDK动态代理
这里只给出代理类和测试类的代码,其他代码与静态代理中的相同。
代理类:DocumentManagerProxy_JDK.java
package com.proxypattern;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @author zdxie
* @Date 上午 9:16 2017/9/6
* @Description 实现InvocationHandler接口,编写invoke方法。所有工作都在invoke方法中完成。
*/
public class DocumentManagerProxy_JDK implements InvocationHandler{
private Logger logger;
private Privilege privilege;
private Object target;
public DocumentManagerProxy_JDK(Logger logger, Privilege privilege, Object target) {
this.logger = logger;
this.privilege = privilege;
this.target = target;
}
//所有工作都在invoke方法中完成
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (this.privilege.getKey().equals("root")){
this.logger.writeLog("权限验证通过!");
//调用目标方法
method.invoke(this.target,args);
this.logger.writeLog("操作成功!");
}else{
System.out.println("Error:没有权限,操作失败!");
this.logger.writeLog("没有权限,操作失败");
}
return null;
}
}
测试方法:
public void testDocument_JDK(){
DocumentManager manager = new DocumentManagerImpl();
Logger logger = new Logger();
Privilege privilege = new Privilege();
privilege.setKey("root");
DocumentManagerProxy_JDK proxy_jdk = new DocumentManagerProxy_JDK(logger,privilege,manager);
//获取代理对象实例
DocumentManager manager_1 = (DocumentManager) Proxy.newProxyInstance(manager.getClass().getClassLoader(),
manager.getClass().getInterfaces(),proxy_jdk);
//在代理对象调用方法的时候,进入了拦截器(代理对象)中的invoke方法
//执行的内容就是拦截器中的invoke方法体的内容
manager_1.readDocument();
manager_1.writeDocument();
}
cglib实现动态代理
代理类:
package com.proxypattern;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @author zdxie
* @Date 下午 2:45 2017/9/6 0006
* @Description 实现cglib提供的MethodInterceptor接口,重写intercept方法,
* 并提供创建代理类的方法createProxy
*/
public class DocumentManagerProxy_cglib implements MethodInterceptor{
private Object target;
private Privilege privilege;
private Logger logger;
public DocumentManagerProxy_cglib(Object target, Privilege privilege, Logger logger) {
this.target = target;
this.privilege = privilege;
this.logger = logger;
}
public Object createProxy(){
Enhancer enhancer = new Enhancer();
//拦截器对象
enhancer.setCallback(this);
//设置代理类的父类为目标类
enhancer.setSuperclass(target.getClass());
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
if (this.privilege.getKey().equals("root")){
this.logger.writeLog("权限验证通过!");
method.invoke(this.target,objects);
this.logger.writeLog("读取成功!");
}else{
System.out.println("Error:没有权限,读取失败!");
this.logger.writeLog("没有权限,读取失败");
}
return null;
}
}
测试方法:
@Test
public void testDocument_JDK(){
DocumentManager manager = new DocumentManagerImpl();
Logger logger = new Logger();
Privilege privilege = new Privilege();
privilege.setKey("root");
DocumentManagerProxy_JDK proxy_jdk = new DocumentManagerProxy_JDK(logger,privilege,manager);
//获取代理对象实例
DocumentManager manager_1 = (DocumentManager) Proxy.newProxyInstance(manager.getClass().getClassLoader(),
manager.getClass().getInterfaces(),proxy_jdk);
manager_1.readDocument();
manager_1.writeDocument();
}
动态代理的优缺点
优点:
1. 能完成对目标类的各种切入操作。
2. 实现了代替目标类完成工作。
3. 分离了目标类和切入类,将工作完全松耦合。
4. 用反射调用目标方法,目标方法变动无需修改代理方法。
5. 没有针对性,新增目标类只需在创建代理对象时传入目标类即可,不用新增代理类。
缺点:
1. 还是需要手动编写拦截器(代理),invoke方法中的逻辑有时还是需要修改。