一、静态代理
从jvm层面来说,静态代理在编译时就将接口、实现类、
代理类变成了一个个class文件
1.静态代理的优点:
1.可以使实现方的业务更加纯粹,不用关注额外的业务
2.代理角色实现额外的业务,完成对公共业务的补充
3.额外业务扩展时方便集中管理
2.静态代理的缺点:
1.每个实现方都需要单独写一个代理方
2.需求方发生变更时,代理方和实现方都需要修改代码,非常不方便
3.静态代理实现步骤:
1.定义一个接口及其实现类
/**
* @description: 需求方接口类
* @author: Jason
* @create: 2021-11-19 10:45
**/
public interface Demander {
/**
* 需求
*/
void doDemand();
}
/**
* @description: 需求方接口类实现类
* @author: Jason
* @create: 2021-11-19 10:47
**/
public class Implementor implements Demander {
@Override
public void doDemand() {
System.out.println("实现方实现需求!");
}
}
2.创建一个代理类同样实现这个接口
/**
* @description: 代理类
* @author: Jason
* @create: 2021-11-19 10:49
**/
public class Proxy implements Demander {
Implementor implementor;
public Proxy(Implementor implementor) {
this.implementor = implementor;
}
public Proxy(){
}
@Override
public void doDemand() {
beforeDemand();
System.out.println("中介代理!");
implementor.doDemand();
afterDemand();
}
void beforeDemand(){
System.out.println("中介代理之前的工作!");
}
void afterDemand(){
System.out.println("中介代理之后的工作!");
}
}
3.将目标对象注入进代理类,然后在代理类的对应方法调用目标类中的对应方法。这样的话,我们就可以通过代理类屏蔽对目标对象的访问,并且可以在目标方法执行前后做一些自己想做的事情。
/**
* @description: 业务入口
* @author: Jason
* @create: 2021-11-19 10:53
**/
public class StartAction {
public static void main(String args[]){
Implementor implementor = new Implementor();
Proxy proxy = new Proxy(implementor);
proxy.doDemand();
}
}
二、动态代理
动态代理实质上是对静态代理的补充及优化
相比静态代理更加灵活,不需要我们必须实现接口类,
甚至可以直接代理实现类(CGLIB动态代理机制)
从 JVM 角度来说,动态代理是在运行时动态生成类字节码,并加载到 JVM 中的。
1.JDK 动态代理 (针对接口,基于反射)
/**
* @description: 公共获取代理对象类
* @author: Jason
* @create: 2021-11-19 14:51
**/
public class DemanderInvocationHandler implements InvocationHandler {
private final Object target;
public DemanderInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String className = target.getClass().getName();
String methodName = method.getName();
log(className,methodName);
Object result = method.invoke(target, args);
return result;
}
public void log(String className,String methodName){
System.out.println("代理对象为"+className+",代理方法为:"+methodName);
}
}
/**
* @description: jdk动态代理对象工厂类
* @author: Jason
* @create: 2021-11-19 15:00
**/
public class JdkProxyFactory {
public static Object getProxy(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(), // 目标类的类加载器
target.getClass().getInterfaces(), // 代理需要实现的接口,可指定多个
new DemanderInvocationHandler(target) // 代理对象对应的自定义 InvocationHandler
);
}
}
/**
* @description: 入口类
* @author: Jason
* @create: 2021-11-19 15:01
**/
public class StartAction {
public static void main(String[] args) {
Demander demander = (Demander) JdkProxyFactory.getProxy(new Implementor());
demander.doDemand();
}
}
2.CGLIB 动态代理 (针对类,基于ASM)
/**
* @description: cglib动态代理类
* @author: Jason
* @create: 2021-11-19 16:36
**/
public class CglibProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
String methodName = method.getName();
String className = o.getClass().getName();
log(className,methodName);
Object result = methodProxy.invokeSuper(o, objects);
return result;
}
public void log(String className,String methodName){
System.out.println("代理对象为"+className+",代理方法为:"+methodName);
}
}
/**
* @description: 入口
* @author: Jason
* @create: 2021-11-19 16:41
**/
public class StartAction {
public static void main(String[] args) {
ImplementorNoSuperClass implementorNoSuperClass = new ImplementorNoSuperClass();
CglibProxy cglibProxy = new CglibProxy();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(implementorNoSuperClass.getClass());
enhancer.setCallback(cglibProxy);
ImplementorNoSuperClass implementorNoSuperClassProxy = (ImplementorNoSuperClass) enhancer.create();
implementorNoSuperClassProxy.doDemand();
}
}
3.javassist 动态代理 (针对类,基于ASM)
/**
* @description: javassist动态代理类
* @author: Jason
* @create: 2021-11-19 17:08
**/
public class JavassistProxy {
private String className;
public JavassistProxy(String className) {
this.className = className;
}
public JavassistProxy(){
}
public void updateDoDemand(String methodName) throws Exception {
ClassPool classPool = ClassPool.getDefault();
CtClass cc = classPool.get(className);
CtMethod method = cc.getDeclaredMethod(methodName);
log(method,methodName);
Object proxyClass = cc.toClass().newInstance();
Method execute = proxyClass.getClass().getMethod("doDemand");
execute.invoke(proxyClass);
}
public void log(CtMethod method,String methodName) throws Exception {
StringBuilder str = new StringBuilder();
str.append("System.out.println(");
str.append("\"代理对象为"+className+",代理方法为:"+methodName);
str.append("\");");
method.insertBefore(str.toString());
}
}
/**
* @description: 入口
* @author: Jason
* @create: 2021-11-19 17:15
**/
public class StartAction {
public static void main(String[] args) {
JavassistProxy javassistProxy = new JavassistProxy("com.design.design_pattern.proxy.ImplementorNoSuperClass");
try {
javassistProxy.updateDoDemand("doDemand");
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
总结
1.spring aop使用的是混合模式,代理对象实现了接口优先使用jdk动态代理,没实现接口则优先使用cglib动态代理
2.cglib动态代理和javasist动态代理都是基于ASM操作字节码实现,其中cglib动态代理是继承目标对象生成一个子类并覆盖方法实现,所以被代理的类不能被final修饰,而javasist动态代理则是直接修改字节码实现。