Spring AOP 之静态代理和动态代理
Spring AOP 之静态代理和动态代理
大家都知道Spring AOP的实现,底层是动态代理,那我们先了解下静态代理和动态代理是怎么工作的吧
静态代理
静态代理就是说我们常说的代理模式,其用途有:
1. 远程代理(Remote Proxy ):为一个对象在不同的地址空间提供局部代理。
2. 虚代理(Virtual Proxy ):根据需要创建开销很大的对象。
3. 保护代理(Protection Proxy ):控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。
4. 智能指引(Smart Reference ):取代了简单的指针,它在访问对象时执行一些附加操作。
类图
代码:
//抽象主题增加了可以返回自身代理对象的方法getProxy()
abstract class Subject02 {
public abstract void request();
public abstract Subject02 getProxy();
}
//被代理者
class RealSubject02 extends Subject02 {
private Subject02 proxy = null;
//被代理者明白自己需要被代理,于是将自己this作为参数找到自己的代理
public RealSubject02() {
this.proxy = new Proxy03(this);
}
public void request() {
System.out.println("被代理者的 request() ...");
}
public Subject02 getProxy() {
return this.proxy;
}
}
//代理者,它是由具体的被代理者指定的
class Proxy03 extends Subject02 {
private Subject02 realSubject = null;
public Proxy03(Subject02 realSubject) {
this.realSubject = realSubject;
}
public void request() {
System.out.println("代理者的 request() ...");
this.realSubject.request();
System.out.println("被代理者操作完成 ...");
}
//代理者本身只是返回自己,当然也可以一直扩展下去
public Subject02 getProxy() {
return this;
}
}
public class Client {
public static void main(String[] args) {
System.out.println("\n第三种代理:强制代理");
Subject02 realSubject = new RealSubject02();
//获得具体被代理者的代理
Subject02 proxy03 = realSubject.getProxy();
proxy03.request();
}
}
测试结果:
第三种代理:强制代理
代理者的 request() ...
被代理者的 request() ...
被代理者操作完成 ...
静态代理的另一种写法:
//抽象主题,定义一系列业务需求处理
abstract class Subject{
public abstract void request();
}
//真实主题,即被代理者
class RealSubject01 extends Subject{
public void request() {
System.out.println("被代理者的 request() ...");
}
}
//代理者
class Proxy01 extends Subject{
private Subject subject = null;
//传进被代理者的方式使得代理者了解自己代理了谁
public Proxy01(Subject realSubject) {
this.subject = realSubject;
}
public void request() {
System.out.println("代理者的 request() ...");
this.subject.request();
System.out.println("被代理者操作完成 ...");
}
}
class Proxy02 extends Subject{
private Subject subject = null;
//直接new 一个被代理者,代理者事先不必知道自己代理了谁,只管负责做好本职工作
public Proxy02() {
this.subject = new RealSubject01();
}
public void request() {
System.out.println("代理者的 request() ...");
this.subject.request();
System.out.println("被代理者操作完成 ...");
}
}
public class Client {
public static void main(String[] args) {
System.out.println("第一种代理:代理者认识被代理者");
Subject proxy01 = new Proxy01(new RealSubject01());
proxy01.request();
System.out.println("\n第二种代理:代理者不认识被代理者");
Subject proxy02 = new Proxy02();
proxy02.request();
}
}
动态代理
动态代理具有更好的灵活性,因为它不用在我们设计实现的时候就指定某一个代理类来代理哪一个被代理对象,我们可以把这种指定延迟到程序运行时由JVM来实现。
更重要的是,动态代理模式可以使得我们在不改变原来已有的代码结构的情况下,对原来的“真实方法”进行扩展、增强其功能,并且可以达到控制被代理对象的行为的目的。
类图:
代码:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//抽象主题类,这里不能用abstract抽象类,一定要是interface
interface AbstractSubject {
public abstract void request();
}
// 真实主题类,即被代理类
class RealSubject implements AbstractSubject {
public void request() {
System.out.println("RealSubject's request() ...");
}
}
// 动态代理类,实现InvocationHandler接口
class DynamicProxy implements InvocationHandler {
// 被代理类的实例
Object obj = null;
// 将被代理者的实例传进动态代理类的构造函数中
public DynamicProxy(Object obj) {
this.obj = obj;
}
/**
* 覆盖InvocationHandler接口中的invoke()方法
*
* 更重要的是,动态代理模式可以使得我们在不改变原来已有的代码结构
* 的情况下,对原来的“真实方法”进行扩展、增强其功能,并且可以达到
* 控制被代理对象的行为,下面的before、after就是我们可以进行特殊
* 代码切入的扩展点了。
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
/*
* before :doSomething();
*/
Object result = method.invoke(this.obj, args);
/*
* after : doSomething();
*/
return result;
}
}
// 测试类
public class Client {
public static void main(String[] args) {
// 被代理类的实例
AbstractSubject realSubject = new RealSubject();
// 获得被代理类的类加载器,使得JVM能够加载并找到被代理类的内部结构,以及已实现的interface
ClassLoader loader = realSubject.getClass().getClassLoader();
// 获得被代理类已实现的所有接口interface,使得动态代理类的实例
Class<?>[] interfaces = realSubject.getClass().getInterfaces();
// 用被代理类的实例创建动态代理类的实例,用于真正调用处理程序
InvocationHandler handler = new DynamicProxy(realSubject);
/*
* loader : 被代理类的类加载器
* interfaces :被代理类已实现的所有接口,而这些是动态代理类要实现的接口列表
* handler : 用被代理类的实例创建动态代理类的实例,用于真正调用处理程序
*
* return :返回实现了被代理类所实现的所有接口的Object对象,即动态代理,需要强制转型
*/
//获得代理的实例
AbstractSubject proxy = (AbstractSubject) Proxy.newProxyInstance(
loader, interfaces, handler);
proxy.request();
//打印出该代理实例的名称
System.out.println(proxy.getClass().getName());
}
}
测试结果:
RealSubject's request() ...
DesignPattern.proxy.dynamicProxy.$Proxy0