【概述】
JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。
InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态地将横切逻辑和业务逻辑编织在一起。
Proxy利用InvocationHandler动态地创建一个符合某一接口的实例,生成目标类的代理对象。
【案例分析】
查看Salary:
1.启动日志
2.启动安全性的框架
3.检查权限:如果有查看工资的权限,则查看工资,否则提示"权限不足"
【工厂截图】
【SalaryManager.java】
package com.HigginCui.proxy.salary; //目标接口 public interface SalaryManager { //查看工资 public void showSalary(); }
【SalaryManagerImpl.java】
package com.HigginCui.proxy.salary; //目标类 public class SalaryManagerImpl implements SalaryManager{ @Override public void showSalary() { System.out.println("Show Salary..."); } }
【Logger.java】
package com.HigginCui.proxy.salary; //日志类 public class Logger { public void logging(){ System.out.println("logging ..."); } }
【Privilege.java】
package com.HigginCui.proxy.salary; //权限类 public class Privilege { private String access; public String getAccess() { return access; } public void setAccess(String access) { this.access = access; } }
【Security.java】
package com.HigginCui.proxy.salary; //安全性框架类 public class Security { public void security(){ System.out.println("security ..."); } }
【SalaryManagerInterceptor.java】
package com.HigginCui.proxy.salary; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; //拦截器 public class SalaryManagerInterceptor implements InvocationHandler{ private Object target; private Logger logger; private Security security; private Privilege privilege;
/**
* target:希望被代理的目标对象
*/ public SalaryManagerInterceptor(Object target,Logger logger,Security security,Privilege privilege){ this.target=target; this.logger=logger; this.security=security; this.privilege=privilege; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //1.开启日志 this.logger.logging(); //2.开启安全性框架类 this.security.security(); //3.检查权限,如果是"admin",则允许查看,否则提示"权限不足" if(this.privilege.getAccess().equals("admin")){ //4.调用目标方法 method.invoke(target, args); //通过java反射间接调用目标对象的方法 }else{ System.out.println("权限不足..."); } return null; } }
【SalaryTest.java】
package com.HigginCui.test; import java.lang.reflect.Proxy; import org.junit.Test; import com.HigginCui.proxy.salary.Logger; import com.HigginCui.proxy.salary.Privilege; import com.HigginCui.proxy.salary.SalaryManager; import com.HigginCui.proxy.salary.SalaryManagerImpl; import com.HigginCui.proxy.salary.SalaryManagerInterceptor; import com.HigginCui.proxy.salary.Security; //模拟客户端 public class SalaryTest { @Test public void testSalart(){ Object target=new SalaryManagerImpl(); //希望被代理的目标对象 Logger logger =new Logger(); Security security=new Security(); Privilege privilege=new Privilege(); /* * 如果是"admin",提示"Show Salary..." * 否则,提示"权限不足" */ privilege.setAccess("admin");
//将目标业务对象target和横切代码编织到一起 SalaryManagerInterceptor interceptor=new SalaryManagerInterceptor(target, logger, security, privilege); /**
* 第1个参数:目标对象target的类加载器
* 第2个参数:目标对象target的需要实现的接口
* 第3个参数:整合了目标对象的和横切代码的编织器对象interceptor
*/
SalaryManager proxy=(SalaryManager) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), interceptor); proxy.showSalary(); } }
【运行结果】
logging ...
security ...
Show Salary...
【分析】
(1)关于InvocationHandler接口
[ invoke(Object proxy,Method method,Object[] args)方法 ]
proxy: 最终生成的代理对象,一般不会用到
method: 被代理目标实例的某个具体方法,通过它可以发起目标实例方法的反射调用
args: 通过被代理的实例的方法的参数,在方法反射调用时使用。
[ 构造方法 ]
构造方法中通过target传入希望被代理的目标对象。
在例子中的接口方法invoke(Object proxy,Method method,Object[] args)方法中,将目标实例传递给method.invoke(target,args)方法,调用目标方法。