代理模式UML类图:
代理模式,旨在代理某个对象的职责,并且可以在职责代理过程中,新增其他辅助方法,代理模式也叫作委托模式。
**Subject抽象主题角色:**被代理角色的抽象角色
**RealSubject具体主题角色:**被代理角色
**Proxy代理角色:**对被代理角色实现方法增强
一、JDK动态代理
JDK动态代理是基于反射原理实现,可以查看JDK提供的InvocationHandler接口和Proxy类
1、被代理对象抽象接口
java
package com.example.demo.proxy;
public interface SubjectInterface {
void coreMethod();
}
2、具体被代理对象
java
package com.example.demo.proxy;
public class Subject implements SubjectInterface {
@Override
public void coreMethod() {
System.out.println("具体角色");
}
}
3、增强被代理对象
java
package com.example.demo.proxy;
public class Advice {
public void before(){
System.out.println("前置处理");
}
public void after(){
System.out.println("后置处理");
}
}
4、JDK动态代理测试
java
package com.example.demo.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkTest {
public static void main(String[] args) {
// 被代理对象
Subject subject = new Subject();
// 增强对象
Advice advice = new Advice();
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
advice.before();
Object invoke = method.invoke(subject, args);
advice.after();
return invoke;
}
};
SubjectInterface proxy = (SubjectInterface) Proxy.newProxyInstance(
subject.getClass().getClassLoader(), // 传入ClassLoader
subject.getClass().getInterfaces(), // 传入要实现的接口
handler); // 传入处理调用方法的InvocationHandler
// 执行方法
proxy.coreMethod();
}
}
在运行期动态创建一个interface
实例的方法如下:
- 定义一个
InvocationHandler
实例,它负责实现接口的方法调用 - 通过
Proxy.newProxyInstance()
创建interface
实例,它需要3个参数:- 使用的
ClassLoader
,通常就是接口类的ClassLoader
- 需要实现的接口数组,至少需要传入一个接口进去
- 用来处理接口方法调用的
InvocationHandler
实例
- 使用的
- 将返回的
Object
强制转型为接口
动态代理实际上是JVM在运行期动态创建class字节码并加载的过程
二、CGLIB动态代理
CGLIB是一个强大的高性能的代码生成包,通过CGLIB的依赖包,可以在程序运行的过程中动态地生成对象和接口,CGLIB底层基于字节码处理框架ASM来转换字节码并生成新的类
1、引入依赖
bash
<!-- https://mvnrepository.com/artifact/cglib/cglib-nodep -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>3.3.0</version>
</dependency>
2、具体被代理对象
java
package com.example.demo.proxy;
public class CglibSubject {
public void coreMethod() {
System.out.println("具体角色");
}
}
3、增强被代理对象
java
package com.example.demo.proxy;
public class Advice {
public void before(){
System.out.println("前置处理");
}
public void after(){
System.out.println("后置处理");
}
}
4、CGLIB动态代理测试
java
package com.example.demo.proxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibTest {
public static void main(String[] args) {
// 被代理对象
CglibSubject cglibSubject = new CglibSubject();
// 增强对象
Advice advice = new Advice();
// 创建增强器
Enhancer enhancer = new Enhancer();
// 设置增强目标类
enhancer.setSuperclass(cglibSubject.getClass());
// 设置回调
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)
throws Throwable {
advice.before();
Object invoke = method.invoke(cglibSubject, args);
advice.after();
return invoke;
}
});
// 创建代理,调用核心方法
CglibSubject targetProxy = (CglibSubject) enhancer.create();
targetProxy.coreMethod();
}
}
三、Spring AOP动态代理
Spring 会根据当前被代理类是否实现了接口进行JDK动态代理和CGLIB动态代理的选择
详见DefaultAopProxyFactory类源码:
java
package org.springframework.aop.framework;
import java.io.Serializable;
import java.lang.reflect.Proxy;
import org.springframework.aop.SpringProxy;
import org.springframework.core.NativeDetector;
import org.springframework.util.ClassUtils;
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
private static final long serialVersionUID = 7930414337282325166L;
public DefaultAopProxyFactory() {
}
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (NativeDetector.inNativeImage() || !config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {
return new JdkDynamicAopProxy(config);
} else {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: Either an interface or a target is required for proxy creation.");
} else {
return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) && !ClassUtils.isLambdaClass(targetClass) ?
new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config));
}
}
}
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return ifcs.length == 0 || ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0]);
}
}