一、代理模式
类A需要完成的工作由类B去完成,类B实际上是在类A的基础上作了一层封装,类B包括原始类A的业务逻辑以及前后的扩展逻辑,实现了类A的功能扩展
类A→被代理类/代理目标类/委托类
类B→代理类
二、静态代理
手动创建代理类,代理类的实现方法中对对原始的业务逻辑进行了扩展,两个要点:
- 代理类、委托类需要实现相同的接口
- 代理类中持有委托类的对象
特点:
- 每进行一次功能扩展,就要对委托类手动创建至少一个相对应的代理类
- 原理简单,但是程序过于繁琐与臃肿
定义一个接口,
package com.imooc.spring.aop.service;
public interface UserService {
public void createUser();
}
委托类,
package com.imooc.spring.aop.service;
public class UserServiceImpl implements UserService{
public void createUser() {
System.out.println("执行创建用户业务逻辑");
}
}
代理类,
package com.imooc.spring.aop.service;
import java.text.SimpleDateFormat;
import java.util.Date;
//静态代理是指必须手动创建代理类的代理模式使用方式
public class UserServiceProxy implements UserService{
//持有委托类的对象
private UserService userService ;
public UserServiceProxy(UserService userService){
this.userService = userService;
}
public void createUser() {
//添加其他的逻辑,实现功能扩展
System.out.println("========静态代理前置扩展功能======");
userService.createUser();
System.out.println("========静态代理后置扩展功能======");
}
}
测试入口类,
package com.imooc.spring.aop;
import com.imooc.spring.aop.service.UserService;
import com.imooc.spring.aop.service.UserServiceImpl;
import com.imooc.spring.aop.service.UserServiceProxy;
import com.imooc.spring.aop.service.UserServiceProxy1;
public class Application {
public static void main(String[] args) {
UserService userService = new UserServiceProxy(new UserServiceImpl());
userService.createUser();
}
}
测试结果,
========静态代理前置扩展功能======
执行创建用户业务逻辑
========静态代理后置扩展功能======
三、动态代理
动态代理分为JDK动态代理、CGLib动态代理
JDK动态代理
接口、委托类沿用上面的Userservice、UserserviceImpl,JDK动态代理需要实现InvocationHandler接口,重写invoke方法 ,
package com.imooc.spring.aop.service;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* InvocationHandler是JDK提供的反射类,用于在JDK动态代理中对目标方法进行增强
* InvocationHandler实现类与切面类的环绕通知类似
*/
public class ProxyInvocationHandler implements InvocationHandler {
private Object target;//目标对象,对所有类生效,所以目标对象类型选择Object
public ProxyInvocationHandler(Object target){
this.target = target;
}
/**
* 在invoke()方法对目标方法进行增强
* @param proxy 代理类对象
* @param method 目标方法对象
* @param args 目标方法实参
* @return 目标方法运行后返回值
* @throws Throwable 目标方法抛出的异常
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("========JDK动态代理前置扩展功能======");
Object ret = method.invoke(target, args);//调用目标方法,类似环绕通知中的ProceedingJoinPoint.proceed()
System.out.println("========JDK动态代理后置扩展功能======");
return ret;
}
}
测试入口类,
package com.imooc.spring.aop;
import com.imooc.spring.aop.service.*;
import java.lang.reflect.Proxy;
public class Application {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
ProxyInvocationHandler invocationHandler = new ProxyInvocationHandler(userService);
//动态创建代理类
//Proxy.newProxyInstance 根据已经存在的接口,实现其相对应的代理类
UserService userServiceProxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),
userService.getClass().getInterfaces(),
invocationHandler);
userServiceProxy.createUser();
}
}
测试结果,
========JDK动态代理前置扩展功能======
执行创建用户业务逻辑
========JDK动态代理后置扩展功能======
JDK动态代理逻辑框图
JDK动态代理主要包括两个步骤:
1.UserService userServiceProxy =Proxy.newProxyInstance();//创建代理类,newProxyInstance()根据已有的接口,生成对应的代理类
2.userServiceProxy.createUser(); //代理类与委托类实现了相同的接口,代理类实现接口中的业务逻辑
1.Proxy.newProxyInstance()在执行步骤:
- 在本地硬盘上创建$Proxy0.class代理类的class文件
- 确定代理类的包名:com.sun.proxy
- 确定代理类的类名:com.sun.proxy.$Proxy0
- ProxyGenerator.generateProxyClass生成代理类的代码,具体可参考图中的伪代码
- defineclass0将硬盘中的.Class字节码文件通过被代理类的classLoder(类加载器),载入到当前JVM的方法区中,并通过new $Proxy0实例化对象,$Proxy0对象中包含UserServiceImpl对象的引用
- 第5步得到代理类的对象userServiceProxy ,至此完成了Proxy.newProxyInstance()的所有工作
动态生成的代理类$Proxy0与委托类UserServiceImpl实现了相同的接口UserService
代理类$Proxy0中包含委托类的对象的引用:targetObject
实现接口中的方法:具体实现代码来自InvocationHandler实现类中的invoke方法
2.调用userServiceProxy.createUser();实现委托类的功能扩展,createUser()中的代码对应伪代码中方法中的业务逻辑
CGLib动态代理
委托类实现了接口,可以通过JDK动态代理实现功能扩展,委托类没有接口,则通过CGLib第三方组件实现功能扩展
CGLib第三方组件继承需要增强的类,产生一个子类,并重写父类中的方法,实现功能扩展
参考文献
1.https://www.cnblogs.com/teach/p/10763845.html