一、概述
1、代理模式是常用的java设计模式,生成一个代理对象,来代替真正的对象,从而控制真实对象的访问。
客户(调用者)----------商务(代理对象)-----------软件工程师(真正对象)
2、我们需要在调用者调用对象之前就生成一个代理对象,而这个代理对象需要和真正对象建立代理关系
-----代理对象和真正对象建立关系
-----实现代理对象的代理逻辑方法
3、常用的代理对象方法:JDK动态代理,CGLIB
二、JDK动态代理
JDK动态代理所用到的代理类在程序调用到代理类对象时才由JVM真正创建,JVM根据传进来的 业务实现类对象以及方法名 ,动态地创建了一个代理类的class文件并被字节码引擎执行,然后通过该代理类对象进行方法调用。
1、需要借助接口生成代理对象
public interface HelloWorld { public void sayHelloWorld(); }
public class HelloWorldImp implements HelloWorld{ @Override public void sayHelloWorld() { System.out.println("你好"); } }
2、实现代理逻辑类:需要实现java.lang,reflect.InvocationHandler接口,重写invoke方法
package reflect; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import org.junit.Test; public class JdkProxyExample implements InvocationHandler{ //真实对象 private Object target = null; //建立关系,返回代理对象 public Object bind(Object target) { this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this); } @Override //处理代理实例上的方法调用并返回结果。当在与其关联的代理实例上调用方法时,将在调用处理程序上调用此方法。 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("调用真实对象服务之前的服务"); Object obj = method.invoke(target, args);//相当于调用sayHelloWorld() System.out.println("调用真实对象服务之后的服务"); return obj; } @Test public void testJdkProxyExample() { JdkProxyExample jdkProxyExample = new JdkProxyExample(); HelloWorld proxy = (HelloWorld) jdkProxyExample.bind(new HelloWorldImp()); proxy.sayHelloWorld(); } }
1、该方法返回指定接口的代理类的实例,该接口将方法调用分派给指定的invocationhandler代理 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException
参数:InvocationHandler是由代理实例的调用处理程序实现的接口。每个代理实例都有一个关联的调用处理程序。当在代理实例上调用方法时,
方法调用被编码并发送到其调用处理程序的invokemethod。
2、Object invoke(Object proxy, Method method,Object[] args) throws Throwable{}
处理代理实例上的方法调用并返回结果。当在与其关联的代理实例上调用方法时,将在调用处理程序上调用此方法。
参数:Object proxy :就是newProxyInstance返回的代理对象
Method method : 当前调度的接口中的方法
Object[] args : 调度方法中的参数
通俗点说就是实现java.lang,reflect.InvocationHandler接口,重写invoke方法,但是重写invoke()需要给它三个参数
参数一:Object proxy :需要通过newProxyInstance返回的获取参数proxy
三、CGLIB动态代理
1、cglib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。因为采用的是继承,所以不能对final修饰的类进行代理。
(1)首先定义一个y业务类Hello
public class Hello { public void sayHello() { System.out.println("hello..."); } }
(2)对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。
package reflect; import java.lang.reflect.Method; import org.junit.Test; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class CGLIBProxyExample implements MethodInterceptor{ //生成代理对象 public Object getProxy(Class cls) { //增强类 Enhancer enhance = new Enhancer(); //设置增强的父类,即业务类 enhance.setSuperclass(cls); /*setCallback()设置哪个类是它的代理类,参数是this为当前对象, * 要求当前对象实现MethodInterceptor接口并实现方法intercept*/ enhance.setCallback(this); return enhance.create(); } @Override public Object intercept(Object proxy,Method method,Object[]args, MethodProxy methodProxy) throws Throwable { System.out.println("前"); Object result = methodProxy.invokeSuper(proxy, args); System.out.println("后"); return result; } @Test public void testCGLIBProxyExample() { CGLIBProxyExample cglibProxyExample = new CGLIBProxyExample(); Hello proxy = (Hello) cglibProxyExample.getProxy(Hello.class); proxy.sayHello(); } }
MethodInterceptor、 Enhancer在cglib-nodep-3.2.10.jar下
四、拦截器
1、因为拦截器可以进一步简化动态代理的使用方法,是程序变得更简单。
2、实现步骤:(1)定义一个拦截器接口
(2)定义拦截器的实现类
(3)实现拦截器的逻辑
public interface Interceptor { 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); }
package interceptor; import java.lang.reflect.Method; public class InterceptorImp implements Interceptor{ @Override /*当返回值为true时,反射真实对象原来的方法 * 当返回值为false时,则调用around方法 */ public boolean before(Object proxy, Object target, Method method, Object[] args) { System.out.println("反射方法前逻辑"); return false; } @Override
//对原来的方法不满意,进行调整 public void around(Object proxy, Object target, Method method, Object[] args) { System.out.println("取代原方法的逻辑"); } @Override public void after(Object proxy, Object target, Method method, Object[] args) { System.out.println("调用原方法或around后还要执行的逻辑"); } }
package interceptor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;public class InterceptorJdkProxy implements InvocationHandler{ private Object target; private String interceptorClass = null;//定义拦截器类路径 public InterceptorJdkProxy(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 InterceptorJdkProxy(target,interceptorClass)); } @Override //第一个参数proxy的获取通过Proxy.newProxyInstance()获取 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(interceptorClass==null) { //没有拦截器就直接反射原来方法 return method.invoke(target, args); } //否则,通过反射生成拦截器 Object result = null; Interceptor interceptor = (Interceptor) Class.forName(interceptorClass).newInstance(); //判断before方法 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; } public static void main(String[] args) { //没有使用代理 HelloWorld helloWorld = new HelloWorldImp(); helloWorld.sayHelloWorld(); //使用了代理 HelloWorld proxy = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImp(), "interceptor.InterceptorImp"); proxy.sayHelloWorld(); } }