一、概述
1、代理模式是常用的java设计模式,生成一个代理对象,来代替真正的对象,从而控制真实对象的访问。
客户(调用者)----------商务(代理对象)-----------软件工程师(真正对象)
2、我们需要在调用者调用对象之前就生成一个代理对象,而这个代理对象需要和真正对象建立代理关系。所以有两个步骤:
(1)代理对象和真正对象建立关系
(2)实现代理对象的代理逻辑方法
3、常用的代理对象方法:JDK动态代理,CGLIB
二、JDK动态代理
JDK动态代理所用到的代理类在程序调用到代理类对象时才由JVM真正创建,JVM根据传进来的业务实现类对象以及方法名 ,动态地创建了一个代理类的class文件并被字节码引擎执行,然后通过该代理类对象进行方法调用。
1、需要借助接口生成代理对象
(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();
}
}
从代码中我们知道,bing()方法返回指定接口的代理类的实例。其中主要是newProxyInstance方法执行操作。
1、看看newProxyInstance()
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)
throws IllegalArgumentException
主要是是三个操作:
- 生成一个实现了参数interfaces里所有接口且继承了Proxy的代理类的字节码,然后用参数里的classLoader加载这个代理类。
- 使用代理类父类的构造函数 Proxy(InvocationHandler h)来创造一个代理类的实例,将我们自定义的InvocationHandler的子类JdkProxyExample传入。通过反射去调newProxyInstanceh方法中传来的h的invoke方法,也就是我们自定义的InvocationHandler的子类中重写的invoke方法。
- 返回这个代理类实例。
看看invoke()方法
Object invoke(Object proxy, Method method,Object[] args) throws Throwable{}
三个参数:
- Object proxy :就是newProxyInstance返回的代理对象
- Method method : 当前调度的接口中的方法
- Object[] args : 调度方法中的参数
三、CGLIB动态代理
1、cglib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。因为采用的是继承,所以不能对final修饰的类进行代理。
1)首先定义一个y业务类Hello:
public class Hello {
public void sayHello() {
System.out.println("hello...");
}
}
(2)对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。
MethodInterceptor、 Enhancer在cglib-nodep-3.2.10.jar下
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();
}
}
四、拦截器
1、因为拦截器可以进一步简化动态代理的使用方法,是程序变得更简单。
2、实现步骤:(1)定义一个拦截器接口
(2)定义拦截器的实现类
(3)实现拦截器的逻辑
1)定义一个拦截器接口
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);
}
2)定义拦截器的实现类
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后还要执行的逻辑");
}
}
(3)实现拦截器的逻辑
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();
}
}