SSM框架中用到的设计模式-动态代理and责任链模式
动态代理模式和责任链模式
代理对象
通过一张图说明:
在软件公司中,客户不会直接找到公司的软件工程师,而是通过商务,和商务谈判,此时的软件工程师是不需要处理谈判的内容,此处的商务就是代理的对象,他代理了软件工程师谈判。
在真实对象(软件工程师)访问之前或之后加入对应逻辑,或其他规则控制是否使用真实对象。
三者的关系:客户(调用者) , 商务(代理对象),软件工程师(真实对象)
常用的动态代理
一般最常用的动态代理分为两种:一种是JDK动态代理,是JDK自带的功能。另一种是CGLIB,这是第三方提供的技术。
JDK动态代理
JDK动态代理通过包java.lang.reflect.*提供方式。必须借助一个借口才能产生代理对象。所以:
public interface HelloWorld{
public void sayHelloWorld();
}
实现接口
public class HelloWorldImpl implements HelloWorld{
@Override
public void sayHelloWorld(){
System.out.println("Hello World");
}
}
要实现代理逻辑类必须去实现java.lang.reflect.InvocationHandler接口,它里面定义了一个invoke方法,并且提供接口数组用于下挂代理对象
//创建一个代理类,通过实现InvocationHandler接口完成
public class JdkProxyExample implements InvocationHandler{
//真实对象(如一开始的图,软件工程师)
private Object target=null;
//建立代理对象和真实对象的代理关系,并且返回代理对象
public Object bind(Object target){
this.target=target;
//通过代理类Proxy的方法newInstance创建代理对象并且返回代理对象
return Proxy.newInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
//代理方法逻辑
@Override
//proxy代理对象,method当前调度方法,args当前方法参数,retrun代理返回结果
public Object invoke(Object proxy,Method method,Object[] args){
System.out.println("进入代理逻辑方法");
System.out.println("在调度真实对象之前的服务");
//相当于调用了sayHelloWord()方法
Object obj=method.invoke(target,args);
System.out.println("在调度真实对象之后的服务");
return obj;
}
}
分析:
-
使用bind方法建立代理对象和现实对象的关系,方法里通过类的属性target保存的真实对象,然后通过代理类的newProxyInstance方法代理对象
其中newProxyInstance方法中的三个参数分别代表:
- 第一个是类加载器,这里采用了target本身的类加载器
- 第二个是把生成代理对象下挂在哪些接口下,这个写法就是放在target实现的接口下
- 第三个是定义实现方法逻辑的代理类,this表示当前对象,它必须实现InvocationHandler接口的invoke方法,他就是代理逻辑方法的实现方法
-
实现代理逻辑方法。invoke方法可以实现代理逻辑,该方法中有三个参数:
- proxy:代理对象,bind方法生产的对象
- method:当前调度方法
- args:调度方法的参数
CGLIB动态代理
这种第三方动态代理优势在于不需要提供接口,只需要一个非抽象类就能实现动态代理。
public class CglibProxyExample implements MethodInterceptor{
//生产CGLIB代理对象
public Object getProxy(Class cls){
//CGLIB enhancer增强类对象
Enhancer enhancer=new Enhancer();
//设置增强类形
enhancer.setSuperclass(cls);
//定义代理逻辑对象为当前对象,要求当前对象实现MethodInterceptor方法
enhancer.setCallback(this);
//生成并返回代理对象
return enhancer.create();
}
//代理逻辑方法
@Override
public Object intercept(Object proxy,Method method,Object[] args,MethodProxy methodProxy)
throws Throwable{
System.out.println("调用真实对象前");
//CGLIB反射调用真实对象方法
Object result=methodProxy.invokeSuper(proxy,args);
System.out.println("调用真实对象后");
return result;
}
}
通过使用CGLIB的增强者Enhancer,通过设置父类方法setSuperclass,在通过setCallback设置哪个类为代理类。intercept方法则是其代理类的逻辑方法。
拦截器
通过JDK动态代理实现拦截器功能,首先要定义接口Interceptor
public interface Interceptor {
//方法的参数为 proxy 理对象,target 真实对象、 method 方法、 args 运行方法参数。
public boolean before (Object proxy , Object target , Method method , Object []args) ;
public void around(Object proxy, Object target , Method method , Object[]args) ;
public void after(Object proxy, Object target, Method method , Object [ ]args);
}
- before方法返回boolean值,当返回true时候,则返回反射真实对象的方法,否则调用around方法
- before方法为false情况下,调用around方法
- 在反射真实对象或执行了around方法之后,调用after方法
实现Interceptor接口
public class Myinterceptor implements Interceptor {
Override
public boolean before (Object proxy , Object target , Method method , Object []args) {
System.err.println (”反射方法前逻辑) ;
return false ;//不反射被代理对象原有方法
}
@Override
public roid after(Object proxy, Object target , Method method , Ob] ect []]args) {
System.err.println ("反射方法后逻辑");
}
@Override
public void around(Object proxy, Object target , Method method , Object[]args) {
System err.println ("取代了被代理对象的方法");
}
}
JDK动态代理中使用拦截器:
public class InterecptorJdkProxy implements InvoctionHandeler{
//真实对象
private Object target;
//拦截器全限定名
private String interceptorClass=null;
public InterecptorJdkProxy(Object target, String interceptorClass){
this.target=target;
this.interceptorClass=interceptorClass;
}
//绑定委托对象并返回一个代理占位
public static Object bind(Object target, String interceptorClass){
//取得代理对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),
new InterecptorJdkProxy(target,interceptorClass));
}
//通过代理对象调用方法,首先进入这个方法
@Override
public Object invoke(Object proxy, Method method, Object []args)throws hrowable{
if(interceptorClass==null){
//没有设置拦截器则直接返回反射原有的方法
return method.invoke(target,args);
}
Object result=null;
//通过反射生成拦截器
Interceptor interceptor=(Interceptor)Class.forName(interceptorClass).newInstance();
//调用前置方法
if(interceptor.before(proxy,target,method,args)){
//反射原有对象方法
result=method.invoke(target,args);
}else{
interceptor.around(proxy,target,method,args);
}
//调用后置方法
interceptor.after(proxy,target,method,args);
return result;
}
}
执行流程:
- 在bind方法中用JDK动态代理绑定一个对象,并返回代理对象
- 如果没有拦截器,则直接返回真实对象的方法,然后结束,否则进入第三步
- 通过反射生成拦截器,并准备使用它
- 调用拦截器before方法,返回为true,反射原来的方法; 否则运行拦截器around方法
- 调用拦截器after方法
- 返回结构
责任链模式
当一个对象在一条链上被多个拦截器拦截处理时,就把这种模式成为责任链模式。