赞
踩
GOF 结构型模式 系列文章
应用场景
主要优点
主要缺点
模式的结构
Subject
)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。Real Subject
)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。Proxy
)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。AOP实现的核心机制
分类
静态代理
:由程序员创建代理类或特定工具自动生成源代码再对其编译,在 程序运行前代理类的 .class
文件就已经存在 了。JDK动态代理
CGLib动态代理
2.1 抽象主题类
/* 声明 被代理类,抽象接口 的业务方法 */
public interface AbstractStar {
void sing(); /* 唱歌 */
}
2.2 真实主题类
/* 被代理类,业务方法的实现类 */
public class Star implements AbstractStar {
@Override
public void sing() { System.out.println("Star::sing()"); }
}
2.3 代理类
/* 代理类,调用被代理类的实现方法 */
public class StaticProxyStar implements AbstractStar {
private AbstractStar star=null;
public StaticProxyStar(AbstractStar star){ this.star = star; }
@Override
public void sing() {
if (star == null) { System.out.println("error!"); }
preSing();
star.sing();
afterSing();
}
public void preSing() { System.out.println("代理类 访问 被代理类 前的预处理"); }
public void afterSing() { System.out.println("代理类 访问 被代理类 后的后续处理"); }
}
2.4 测试
public class StaticProxyTest {
public static void main(String[] args) {
Star star1 = new Star();
ProxyStar proxy = new ProxyStar(star1);
proxy.sing();
}
}
测试结果如下
InvocationHandler
接口;Proxy.newProxyInstance
产生代理对象;3.1 抽象主题类:使用2.1
中的AbstractStar
接口
3.2 真实主题类: 使用2.2
中的Star
实现类
3.3 代理类
InvocationHandler
接口来自定义自己的InvocationHandler
;Proxy.newProxyInstance
方法内部通过Proxy.getProxyClass
获得动态代理类;Proxy.newProxyInstance
方法内部通过反射机制
获得代理类的构造方法,方法签名为getConstructor(InvocationHandler.class)
;InvocationHandler
实例对象传为参数传入;import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class JDKProxyStar implements InvocationHandler { private Object target = null; // 真实对象 /** * 建立代理对象(代理类)、真实对象(被代理)的代理关系,并返回代理对象 * @param target 真实对象 * @return 代理对象 */ public Object bind(Object target){ this.target = target; return Proxy.newProxyInstance( target.getClass().getClassLoader(), // 类加载器 target.getClass().getInterfaces(), // 挂在哪些类接口下 this); // 定义实现方法逻辑的代理类 } /** * 代理方法逻辑 * @param proxy 代理对象 * @param method 当前调度方法 * @param args 当前调度方法的参数 * @return 代理结果返回 * @throws Throwable 异常 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理对象 访问 被代理对象 前的预处理"); if(method.getName().equals("sing")){ method.invoke(target, args); } System.out.println("代理对象 访问 被代理对象 后的后续处理"); return null; } }
3.4 测试
public class JDKProxyTest {
public static void main(String[] args) {
AbstractStar star = new Star();
JDKProxyStar jdkProxy = new JDKProxyStar();
// 绑定关系,挂在 AbstractStar 接口下,所以声明代理对象 AbstractStar proxy
AbstractStar proxy = (AbstractStar) jdkProxy.bind(star);
proxy.sing();
}
}
测试结果如下
环境构建
cglib-2.2.2.jar
、asm-3.3.1.jar
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
基本介绍
cglib是一个java字节码的生成工具,它动态生成一个被代理类的子类,
子类重写被代理类的所有不是final的方法。
即 cglib无法代理被final修饰的类或方法以及静态方法。
在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。
CGLIB基于ASM框架实现,是JDK动态代理的有效补充,可以用于AOP编程,比如日志打印、安全控制、统一鉴权等
4.1 抽象主题类:使用2.1
中的AbstractStar
接口
4.2 真实主题类: 使用2.2
中的Star
实现类
4.3 代理类
import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /* 实现MethodInterceptor接口生成方法拦截器 */ public class CGLibProxyInterceptor implements MethodInterceptor { /** * * @param obj 表示要进行增强的对象 * @param method 表示拦截的方法 * @param objects 数组表示参数列表,基本数据类型需要传入其包装类型,如int-->Integer、long-Long、double-->Double * @param methodProxy 表示对方法的代理,invokeSuper方法表示对被代理对象方法的调用 * @return 执行结果 * @throws Throwable 异常 */ public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { before(method.getName()); /* 注意这里是调用invokeSuper而不是invoke,否则死循环 */ // methodProxy.invokeSuper执行的是原始类的方法; // method.invoke执行的是子类的方法; Object result = methodProxy.invokeSuper(obj, objects); after(method.getName()); return result; } /* 调用invoke方法之前执行 */ private void before(String methodName) { System.out.println("代理对象 访问 被代理对象 前的预处理"); } /* 调用invoke方法之后执行 */ private void after(String methodName) { System.out.println("代理对象 访问 被代理对象 后的后续处理"); } }
4.4 测试
import net.sf.cglib.proxy.Enhancer; public class CGLibProxyTest { public static void main(String[] args) { // 通过CGLIB动态代理获取代理对象的过程 // 1. 创建Enhancer对象,类似于JDK动态代理的Proxy类 Enhancer enhancer = new Enhancer(); // 继承被代理类 // 2. 设置目标类的字节码文件 enhancer.setSuperclass(Star.class); // 3. 设置回调函数 enhancer.setCallback(new CGLibProxyInterceptor()); // 4. 设置代理类对象 // create方法正式创建代理类 Star star = (Star)enhancer.create(); //在调用代理类中方法时会被我们实现的方法拦截器进行拦截 star.sing(); } }
测试结果如下
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。