【动态代理】底层实现的小例
我们来谈谈什么是动态代理。假设这样一个场景:
你们是一家软件公司,你是一位软件工程师。现在又客户带着一个需求来找你们公司做项目。显然不是找你直接谈,而是去找商务去谈,此时客户就会认为商务就代表你们公司。然后当客户与商务交流的差不多了,商务就会来找你接洽。显然商务与工程师之间是代理与被代理的关系。
Spring中通常用JDK和CGLIB。Mybatis中还是用了javassist
- JDK与CGLIB
jdk动态代理中,我们必须使用借口。而cglib则不需要。
下面我们讨论梁中最常用的代理:
JDK动态代理:
他必须通过接口才能生成代理对象,首先我们先生成一个接口
package com.rick.proxy;
public interface Hello {
public void sayHello();
}
然后提供接口的实现类
package com.rick.proxy;
public class HelloImpl implements Hello{
@Override
public void sayHello() {
System.out.println("say Hello......");
}
}
此时我们就可以开始动态代理了,分为两个步骤:
- 首先建立起代理对象和真是对象的关系
- 然后实现代理逻辑
package com.rick.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
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);
/*
* 第一个参数是累的加载器,我们采用了target本身的类加载器
* 第二个参数是吧生成的动态代理对象挂在哪些接口下面
* 第三个表示定义实现方法逻辑的代理类,this表示当前对象他必须
* 实现InvocationHandler的invoke方法,他就是代理逻辑方法的实现方法
*/
}
//实现代理逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/*
* proxy为代理对象,就是bind方法生成的对象
* method为当前调度的方法
* args为调度方法的参数
*/
System.out.println("进入代理逻辑方法");
System.out.println("在调度真实对象之前。。");
Object obj = method.invoke(target, args);//相当于调用sayHello方法
System.out.println("在调度真实对象之后。。");
return obj;
}
}
类比前面的例子,proxy相当于商务对象,target相当于软件工程师对象,bind方法就是建立商务和软件工程师代理关系的方法。而invoke就是商务逻辑,他控制软件工程师的访问
测试
package com.rick.proxy;
public class Test {
public static void main(String[] args) {
JdkProxy();
}
private static void JdkProxy() {
JdkProxyExample jdkProxyExample = new JdkProxyExample();
Hello proxy = (Hello) jdkProxyExample.bind(new HelloImpl());
proxy.sayHello();
}
}
CGLIB动态代理:
jkd动态代理必须提供接口才能使用,在一些不能提供接口的场景中,只能采取第三方技术。比如CGLIB动态代理。它的优势在于不需要提供接口,只要一个非抽象类就能实现动态代理。
例如:
package com.rick.proxy;
public class UserImpl {
public void sayHello(String name) {
System.out.println("Hello:"+name);
}
}
他不存在实现任何借口,所以没有办法使用JDK动态代理,之力就要采用CGLIB动态代理
package com.rick.proxy;
import java.lang.reflect.Method;
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) {
// 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;
}
}
创建测试:
package com.rick.proxy;
public class Test {
public static void main(String[] args) {
// JdkProxy();
CGLIBProxy();
}
// private static void JdkProxy() {
// JdkProxyExample jdkProxyExample = new JdkProxyExample();
// Hello proxy = (Hello) jdkProxyExample.bind(new HelloImpl());
// proxy.sayHello();
// }
public static void CGLIBProxy() {
CglibProxyExample cglibProxyExample = new CglibProxyExample();
UserImpl proxy = (UserImpl) cglibProxyExample.getProxy(UserImpl.class);
proxy.sayHello("zhangsan");
}
}
浙公网安备 33010602011771号