Java基础干货动态代理核心代码
Posted 在路上的德尔菲
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java基础干货动态代理核心代码相关的知识,希望对你有一定的参考价值。
JDK动态代理
//自定义的接口类,JDK动态代理的实现必须有对应的接口类
public interface ExInterface {
void execute();
}
//A类,实现了ExInterface接口类
public class A implements ExInterface{
public void execute(){
System.out.println("执行A的execute方法...");
}
}
//代理类的实现
public class JDKProxy implements InvocationHandler{
/**
* 要被代理的目标对象
*/
private A target;
public JDKProxy(A target){
this.target=target;
}
/*
* 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数 第一个参数
* handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
* 第二个参数realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,
* 表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了 第三个参数handler, 我们这里将这个代理对象关联到了上方的
* InvocationHandler 这个对象上
*/
public ExInterface createProxy(){
return (ExInterface) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
/**
* 调用被代理类(目标对象)的任意方法都会触发invoke方法
* @param proxy 代理类
* @param method 被代理类的方法
* @param args 被代理类的方法参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//过滤不需要该业务的方法
if("execute".equals(method.getName())) {
//调用前验证权限
AuthCheck.authCheck();
//调用目标对象的方法
Object result = method.invoke(target, args);
//记录日志数据
Report.recordLog();
return result;
}eles if("delete".equals(method.getName())){
//.....
}
//如果不需要增强直接执行原方法
return method.invoke(target,args);
}
}
//测试验证
public static void main(String args[]){
A a=new A();
//创建JDK代理
JDKProxy jdkProxy = new JDKProxy(a);
//创建代理对象
//proxy.getClass().getName()为com.sun.proxy.$Proxy0格式
ExInterface proxy = jdkProxy.createProxy();
//执行代理对象方法
proxy.execute();
}
核心类是java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler,都是反射包里面的。
注意通过 Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,JDK中有个规范,只要要是$
开头的.class文件,一般都是自动生成的并且命名方式都是这样的形式,以$
开头,proxy为中,最后一个数字表示对象的标号。
JDK动态代理原理
JDK采用字节重组,重新生成对象来替代原始对象,以达到动态代理的目的,JDK动态代理生成对象的步骤如下:
- 拿到被代理对象的引用,然后获取他的接口 (Proxy.getInstance方法) ,反射获取
- JDK代理重新生成一个类,同时该类实现我们给的代理对象所实现的接口
- 动态生成java代码,新加的业务逻辑方法由一定的逻辑代码调用(在代码中体现)
- 编译新生成java代码的class文件
- 重新加载到JVM中运行
cglib动态代理
//被代理的类即目标对象
public class A {
public void execute(){
System.out.println("执行A的execute方法...");
}
}
//代理类
public class CGLibProxy implements MethodInterceptor {
/**
* 被代理的目标类
*/
private A target;
public CGLibProxy(A target) {
super();
this.target = target;
}
/**
* 创建代理对象
* @return
*/
public A createProxy(){
// 使用CGLIB生成代理:
// 1.声明增强类实例,用于生产代理类
Enhancer enhancer = new Enhancer();
// 2.设置被代理类字节码,CGLIB根据字节码生成被代理类的子类
enhancer.setSuperclass(target.getClass());
// 3.//设置回调函数,即一个方法拦截
enhancer.setCallback(this);
// 4.创建代理:
return (A) enhancer.create();
}
/**
* 回调函数
* @param proxy 代理对象
* @param method 委托类方法
* @param args 方法参数
* @param methodProxy 每个被代理的方法都对应一个MethodProxy对象,
* methodProxy.invokeSuper方法最终调用委托类(目标类)的原始方法
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//过滤不需要该业务的方法
if("execute".equals(method.getName())) {
//调用前验证权限(动态添加其他要执行业务)
AuthCheck.authCheck();
//调用目标对象的方法(执行A对象即被代理对象的execute方法)
Object result = methodProxy.invokeSuper(proxy, args);
//记录日志数据(动态添加其他要执行业务)
Report.recordLog();
return result;
}else if("delete".equals(method.getName())){
//.....
return methodProxy.invokeSuper(proxy, args);
}
//如果不需要增强直接执行原方法
return methodProxy.invokeSuper(proxy, args);
}
}
作者:极乐君
链接:https://zhuanlan.zhihu.com/p/25522841
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
详细:https://www.cnblogs.com/duanxz/archive/2012/12/03/2799504.html
以上是关于Java基础干货动态代理核心代码的主要内容,如果未能解决你的问题,请参考以下文章