2021-02-03
Java的代理proxy机制
代理必须分为两个步骤: * 1. 代理对象和真实对象建立代理关系 * 2. 实现代理对象的代理逻辑方法
主要是通过两种方法:
1. JDK动态代理
JDK动态代理是java.lang.reflect.*包提供的方式,它必须借助一个接口才能产生代理对象,所以先定义接口。JDK动态代理中,要实现代理逻辑类必须去实现java.lang.reflect.InvocationHandler接口,
它里面定义了一个invoke方法,并提供接口数组用于下挂代理对象。
2. CGLIB动态代理
CGLIB动态代理,它的优势在于不需要提供接口,只要一个非抽象类就能实现动态代理。
但需要引入jar包或者 maven 的 pom.xml中添加:
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>
1. JDK动态代理
我们通过代码来看,主要包括4个java文件。
HelloWorld:测试文件接口
HelloWorldImpl:测试文件的实现
JdkProxyExample:实现代理
TestJdkProxy:测试代理
1) HelloWorld 测试文件接口
package cn.zc.javapro.mechanism.proxy.jdk; public interface HelloWorld { public void sayHelloWorld(); }
2)HelloWorldImpl 测试文件的实现
package cn.zc.javapro.mechanism.proxy.jdk; public class HelloWorldImpl implements HelloWorld { @Override public void sayHelloWorld() { System.out.println("Hello World!"); } }
3)JdkProxyExample:实现代理
package cn.zc.javapro.mechanism.proxy.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /* * 代理必须分为两个步骤: * 1. 代理对象和真实对象建立代理关系 * 2. 实现代理对象的代理逻辑方法 */ /* * JDK动态代理是java.lang.reflect.*包提供的方式,它必须借助一个接口才能产生代理对象,所以先定义接口。 */ /* * JDK动态代理中,要实现代理逻辑类必须去实现java.lang.reflect.InvocationHandler接口, * 它里面定义了一个invoke方法,并提供接口数组用于下挂代理对象。 */ public class JdkProxyExample implements InvocationHandler { //真实对象 private Object target = null; /** * 1. 建立代理对象和真实对象的代理关系,并返回代理对象 * @param target 真实对象 * @return 代理对象 */ public Object bind(Object target) { this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } /** * 2.代理方法逻辑 * @param proxy 代理对象 * @param method 当前调度方法 * @param args 当前方法参数 * @return 代理结果返回 * @throws Throwable 异常 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("进入代理逻辑方法"); System.out.println("在调度真实对象之前的服务"); Object obj = method.invoke(target, args); //相当于调用sayHelloWorld方法 System.out.println("在调度真实对象之后的服务"); return obj; } }
4)TestJdkProxy:测试代理
package cn.zc.javapro.mechanism.proxy.jdk; public class TestJdkProxy { public static void main(String[] args) { JdkProxyExample jdk = new JdkProxyExample(); //绑定关系,因为挂在接口HelloWorld下,所以声明代理对象HelloWorld proxy HelloWorld proxy = (HelloWorld)jdk.bind(new HelloWorldImpl()); //注意,此时HelloWorld对象已经是一个代理对象,它会进入代理的逻辑方法invoke里 proxy.sayHelloWorld(); //相当于下面这段代码 /* try { jdk.invoke(proxy, HelloWorldImpl.class.getMethod("sayHelloWorld", null), null); } catch (Throwable e) { e.printStackTrace(); }*/ } }
2. CGLIB动态代理
我们通过代码来看,主要包括3个java文件。
HelloImpl:测试类
CglibProxyExample :代理实现类
TestCGLIBProxy:测试代理类
1)HelloImpl:测试类
package cn.zc.javapro.mechanism.proxy.cglib; public class HelloImpl { public void sayHello(String name) { System.out.println("Hello " + name); } }
2)CglibProxyExample :代理实现类
package cn.zc.javapro.mechanism.proxy.cglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; /* * 代理必须分为两个步骤: * 1. 代理对象和真实对象建立代理关系 * 2. 实现代理对象的代理逻辑方法 */ /*需要引入 <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency> */ // CGLIB动态代理,它的优势在于不需要提供接口,只要一个非抽象类就能实现动态代理 public class CglibProxyExample implements MethodInterceptor { /** * 生成CGLIB代理对象 * @param cls -- Class类 * @return Class类的CGLIB代理对象 */ public Object getProxy(Class cls) { //CGLIB enhancer 增强类对象 Enhancer enhancer = new Enhancer(); // 设置增强类型 enhancer.setSuperclass(cls); // 定义代理逻辑对象为当前对象,要求当前对象实现MethodInterceptor方法 enhancer.setCallback(this); // 生成并返回代理对象 return enhancer.create(); } /** * 代理逻辑方法 * @param proxy 代理对象 * @param method 方法 * @param args 方法参数 * @param methodProxy 方法代理 * @return 代理逻辑返回 * @throws Throwable 异常 */ @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; } }
3)TestCGLIBProxy:测试代理类
package cn.zc.javapro.mechanism.proxy.cglib; public class TestCGLIBProxy { public static void testCGLIBProxy() { CglibProxyExample cpe = new CglibProxyExample(); HelloImpl obj = (HelloImpl)cpe.getProxy(HelloImpl.class); obj.sayHello("zhangsan"); } public static void main(String[] args) { testCGLIBProxy(); } }