JAVA 静态代理和动态代理
应用场合实例:权限管理
模拟需求:对业务bean里的所有方法进行拦截,拦截到方法之后判断用户是否有权限调用这个方法(判断依据:用户是否为null)
步骤一:先定义一个接口类
package proxy.service;
public interfacePersonService {
public voidsave(String name);
public voidupdate(String name, Integer personid);
}
步骤二:定义一个接口实现类
package proxy.service.impl;
import proxy.service.PersonService;
public class PersonServiceBean implementsPersonService{
privateString user = null;//提供一个用户
publicPersonServiceBean(){}
publicPersonServiceBean(String user){ this.user= user; }
publicString getUser() { return this.user;} //向外暴露一个获得用户的方法
Public voidsave(String name) { System.out.println("我是save()方法");}
Public voidupdate(String name, Integer personid) { System.out.println("我是update()方法");}
}
实现方案1:
if(user != null)
缺点:如果要控制更多的业务bean里的业务方法,出现在各个业务方法里面去,代码写死不灵活,侵入性强。且权限判断依据一旦发生改变,所有业务方法里面的判断代码都需要修改。
改进1:过滤器(限于web应用)
改进2:采用代理设计模式(拦截并在拦截之后做相应的处理)【设计理念】
客户端应用-------------------------------》代理对象----------------------------------------》目标对象
客户端应用调用实际的目标对象之前先经过代理对象,也就是说客户端调用的是代理对象,代理对象实现了目标对象的所有接口,通过代理对象的调用,它会把方法的调用委派给目标对象,更形象的说,代理方法的内部调用了目标对象的方法,不需要在目标对象里编写判断代码,只需要在处理代理对象里面,目标对象调用之前做一个权限的判断,如果有权限才在代理对象里面调用目标对象的方法,如果没有权限就不调用目标对象的方法。
两种代理:静态代理和动态代理
实现方案2:
静态代理
package proxy.service.impl;
import proxy.service.PersonService;
public class StaticProxy implements PersonService {
privatePersonService personService;
publicStaticProxy(PersonService personService){ this.personService=personService;}
publicvoid save(String name) {
PersonServiceBeanbean = (PersonServiceBean)this.personService;
if(bean.getUser()!=null){bean.save(name);}
}
Public voidupdate(String name, Integer personid) {
PersonServiceBeanbean = (PersonServiceBean)this.personService;
if(bean.getUser()!=null){ bean.update(name, personid);}
}
}
缺点:对于接口中的每一个方法,所用的实现类和代理类都需要做个实现,增加了代码的复杂度。
实现方案3:
动态代理
好处:接口中声明的所有方法都被转移到一个集中的方法中处理(invoke),不需要对接口中的每一个方法进行中转,动态代理类只能代理接口,且都需实现invocationhandler接口,覆盖invoke方法,该incoke方法就是调用被代理接口的所有方法时需要调用的。
JDK动态生成代理对象的字节码
Proxy为目标对象动态创建代理对象,应用前提:目标对象必须面向接口
思考的步骤属于“横切性关注点”
importjava.lang.reflect.InvocationHandler;
importjava.lang.reflect.Method;
importjava.lang.reflect.Proxy;
importproxy.service.impl.PersonServiceBean;
publicclass JDKProxyFactory implementsInvocationHandler{
private Object targetObject;
public Object createProxyIntance(Object targetObject){
this.targetObject= targetObject;
return Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(),
this.targetObject.getClass().getInterfaces(),this);
//new一个代理实例,参数1为目标对象的类装载器,2为代理对象要实现的接口(创建目标对象的代理类,所以要实现目标对象里所有的接口,那么创建的代理对象会把这里面的接口全部实现),3为接口,回调,拦截到方法的时候会触发哪一个类的拦截方法,要求必修实现InvocationHandler接口
}
PublicObject invoke(Object proxy, Method method, Object[] args) {
//1为代理对象,2为被拦截到的方法,3为方法的输入参数
当客户端调用代理对象的方法时会调用this里面由InvocationHandler接口决定的invoke方法。委派给目标对象
PersonServiceBean bean = (PersonServiceBean) this.targetObject;
Object result = null;
if(bean.getUser()!=null){ result=method.invoke(targetObject, args);}
return result;
}
}
Test
packagejunit.test;
publicclass ProxyTest {
@Test
public voidproxyTest(){
JDKProxyFactoryfactory = new JDKProxyFactory();
PersonService service = (PersonService)factory.createProxyIntance(newPersonServiceBean("xxx"));
service.save("888");
}
}