本篇博客参考《架构探险 -- 从零开始写 java Web 框架》4.3 章节
1 代理接口:
- package smart.myaop.framework;
- public interface Proxy {
- /**
- * 执行链式调用
- */
- Object doProxy(ProxyChain proxyChain) throws Throwable;
- }
2 代理链(责任链模式, 同一个对象可以被多个 Proxy 层层代理):
- package smart.myaop.framework;
- import.NET.sf.cglib.proxy.MethodProxy;
- import java.lang.reflect.Method;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * 代理链
- */
- public class ProxyChain {
- private final Class<?> targetClass; // 目标类
- private final Object targetObject; // 目标对象
- private final Method targetMethod; // 目标方法
- private final MethodProxy methodProxy; // 方法代理, cglib 提供的方法代理对象
- private final Object[] methodParams; // 方法参数
- private List<Proxy> proxyList = new ArrayList<>(); // 代理列表
- private int proxyIndex = 0; // 代理索引
- public ProxyChain(Class<?> targetClass, Object targetObject, Method targetMethod, MethodProxy methodProxy, Object[] methodParams, List<Proxy> proxyList) {
- this.targetClass = targetClass;
- this.targetObject = targetObject;
- this.targetMethod = targetMethod;
- this.methodProxy = methodProxy;
- this.methodParams = methodParams;
- this.proxyList = proxyList;
- }
- public Class<?> getTargetClass() {
- return targetClass;
- }
- public Method getTargetMethod() {
- return targetMethod;
- }
- public Object[] getMethodParams() {
- return methodParams;
- }
- /**
- * 在 Proxy 接口的实现中提供相应横切逻辑并调用 doProxyChain 方法
- * methodProxy 的 invokeSuper 方法执行目标对象的业务逻辑
- * @return
- * @throws Throwable
- */
- public Object doProxyChain() throws Throwable {
- Object methodResult;
- if(proxyIndex <proxyList.size()) {
- methodResult = proxyList.get(proxyIndex++).doProxy(this);
- } else {
- methodResult = methodProxy.invokeSuper(targetObject, methodParams);
- }
- return methodResult;
- }
- }
3 创建代理对象的工具类:
- package smart.myaop.framework;
- import.NET.sf.cglib.proxy.Enhancer;
- import.NET.sf.cglib.proxy.MethodInterceptor;
- import.NET.sf.cglib.proxy.MethodProxy;
- import java.lang.reflect.Method;
- import java.util.List;
- /**
- * 代理管理器, 输入目标类和一组 proxy 接口实现, 创建一个代理对象并输出
- * 由切面类来调用 ProxyManager 创建代理链, 切面类在目标方法调用前后进行增强
- *
- * 在框架里使用 ProxyManager 创建代理对象并放入 IoC 容器, 然后将代理对象注入到其它对象中
- */
- public class ProxyManager {
- public static <T> T createProxy(final Class<?> targetClass, final List<Proxy> proxyList) {
- return (T) Enhancer.create(targetClass, new MethodInterceptor() {
- @Override
- public Object intercept(Object targetObject, Method targetMethod, Object[] methodParams, MethodProxy methodProxy) throws Throwable {
- return new ProxyChain(targetClass, targetObject, targetMethod, methodProxy, methodParams, proxyList);
- }
- });
- }
- }
4Proxy 接口的抽象实现, 模板方法模式:
- package smart.myaop.framework;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import java.lang.reflect.Method;
- /**
- * 切面代理
- * 该抽象类提供模板方法, 由其子类扩展相应的抽象方法
- */
- public abstract class AspectProxy implements Proxy {
- private static final Logger logger = LoggerFactory.getLogger(AspectProxy.class);
- @Override
- public Object doProxy(ProxyChain proxyChain) throws Throwable {
- Object result = null;
- Class<?> cls = proxyChain.getTargetClass();
- Method method = proxyChain.getTargetMethod();
- Object[] params = proxyChain.getMethodParams();
- /**
- * 从 proxyChain 中获取目标类, 目标方法和目标参数, 通过 try ... catch ...finally 代码块调用代理框架
- */
- begin();
- try {
- if(intercept(cls, method, params)) {
- before(cls, method, params);
- result = proxyChain.doProxyChain();
- after(cls, method, result);
- }
- } catch (Exception e) {
- logger.error("proxy failure", e);
- error(cls, method, params, e);
- } finally {
- end();
- }
- return result;
- }
- /**
- * 下面几个都是钩子方法, 可在子类中有选择性的实现, 可以有选择性的实现, 所以不定义成抽象方法
- */
- public boolean intercept(Class<?> cls, Method method, Object[] params) {
- return true;
- }
- public void before(Class<?> cls, Method method, Object[] params) {}
- public void after(Class<?> cls, Method method, Object result) {}
- public void begin() {}
- public void end() {}
- public void error(Class<?> cls, Method method, Object[] params, Exception e) {}
- }
5 举例某个具体的 Proxy 实现:
- package smart.myaop;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.stereotype.Controller;
- import smart.myaop.framework.AspectProxy;
- import java.lang.reflect.Method;
- /**
- * 该示例类继承 AspectProxy 类, 指定拦截 Controller 所有方法, 并在方法前后加日志并记录执行时间
- */
- @Aspect(Controller.class)
- public class ControllerAspect extends AspectProxy {
- private static final Logger logger = LoggerFactory.getLogger(ControllerAspect.class);
- private long begin;
- @Override
- public void before(Class<?> cls, Method method, Object[] params) {
- logger.debug("----------begin----------");
- logger.debug(String.format("class: %s"), cls.getName());
- logger.debug(String.format("method: %s"), method.getName());
- begin = System.currentTimeMillis();
- }
- @Override
- public void after(Class<?> cls, Method method, Object result) {
- logger.debug(String.format("time: %dms"), System.currentTimeMillis() - begin);
- logger.debug("----------end----------");
- }
- }
6 自定义注解 @Aspect, 作为代理标记:
- package smart.myaop;
- import java.lang.annotation.*;
- /**
- * 切面注解
- */
- @Target(ElementType.TYPE) // 只能用在类上
- @Retention(RetentionPolicy.RUNTIME)
- public @interface Aspect {
- /**
- * 注解, 注解类, 用来定义注解
- * @return
- */
- Class<? extends Annotation> value();
- }
7 初始化框架并创建代理对象放入 IoC 容器:
- package smart.myaop;
- import smart.myaop.framework.AspectProxy;
- import smart.myaop.framework.Proxy;
- import smart.myaop.framework.ProxyManager;
- import java.lang.annotation.Annotation;
- import java.util.*;
- /**
- * 初始化时获取所有目标类和其被拦截的切面类实例, 获取 AspectProxy 抽象类的所有子类和 @Aspect 注解的所有类
- * 调用 ProxyManager#createProxy 方法创建代理对象放入 IoC 容器
- * AopHelper 在框架初始化时调用, 要在初始化 bean 之后, IoC 容器初始化之前调用, 这样 IoC 容器做属性注入时候才能拿到相应的代理对象
- */
- public class AopHelper {
- private static Set<Class<?>> allClassSet = new HashSet<>(); // 项目启动时把指定路径下的所有 class 文件加载为 class 对象集合, 过程略
- static {
- try {
- Map<Class<?>, Set<Class<?>>> proxyMap = createProxyMap();
- Map<Class<?>, List<Proxy>> targetMap = createTargetMap(proxyMap);
- for (Map.Entry<Class<?>, List<Proxy>> targetEntry : targetMap.entrySet()) {
- Class<?> targetClass = targetEntry.getKey();
- List<Proxy> proxyList = targetEntry.getValue();
- Object proxy = ProxyManager.createProxy(targetClass, proxyList);
- //todo 放入 targetClass 为键, proxy 为值放入 IoC 容器, 在 IoC 容器做属性注入的时候通过 class 对象拿到的就是代理对象了
- }
- } catch (Exception e) {
- System.out.println("aop failure");
- e.printStackTrace();
- }
- }
- /**
- * 目标类与代理对象列表之间的映射关系, 如一个业务类被多个 @Aspect 注解修饰的 AspectProxy 子类代理, 这里得到这样的 1 对 n 映射关系
- * @param proxyMap
- * @return
- * @throws Exception
- */
- private static Map<Class<?>, List<Proxy>> createTargetMap(Map<Class<?>, Set<Class<?>>> proxyMap) throws Exception {
- Map<Class<?>, List<Proxy>> targetMap = new HashMap<>();
- for (Map.Entry<Class<?>, Set<Class<?>>> proxyEntry : proxyMap.entrySet()) {
- Class<?> proxyClass = proxyEntry.getKey();
- Set<Class<?>> targetClassSet = proxyEntry.getValue();
- for (Class<?> targetClass : targetClassSet) {
- Proxy proxy = (Proxy) proxyClass.newInstance();
- if(targetMap.containsKey(targetClass)) {
- targetMap.get(targetClass).add(proxy);
- } else {
- List<Proxy> proxyList = new ArrayList<>();
- proxyList.add(proxy);
- targetMap.put(targetClass, proxyList);
- }
- }
- }
- return targetMap;
- }
- /**
- * 给 createTargetMap 方法用
- * 代理类 (切面类) 与目标类集合之间的一对多映射关系
- * 在全部 class 对象集合中搜索满足 1 是 AspectProxy 子类, 2 被 @Aspect 注解, 这样的类(代理类), 根据 @Aspect 注解指定的注解属性去获取该注解对应的目标类集合
- * 然后建立代理类与目标类集合之间的映射关系, 据此分析出目标类与代理对象列表之间的映射关系
- * @return
- * @throws Exception
- */
- private static Map<Class<?>, Set<Class<?>>> createProxyMap() throws Exception {
- Map<Class<?>, Set<Class<?>>> proxyMap = new HashMap<>();
- Set<Class<?>> proxyClassSet = new HashSet<>();
- for (Class<?> aClass : allClassSet) {
- if(AspectProxy.class.isAssignableFrom(aClass) && !AspectProxy.class.equals(aClass)) {
- proxyClassSet.add(aClass); // 获取 AspectProxy 子类 class 对象集合
- }
- }
- for (Class<?> aClass : proxyClassSet) {
- if(aClass.isAnnotationPresent(Aspect.class)) {
- Aspect aspect = aClass.getAnnotation(Aspect.class);
- Set<Class<?>> targetClassSet = createTargetClassSet(aspect);
- proxyMap.put(aClass, targetClassSet);
- }
- }
- return proxyMap;
- }
- /**
- * 给 createProxyMap 方法用
- * 获取被指定 aspect 注解的所有类对象
- * @param aspect
- * @return
- * @throws Exception
- */
- private static Set<Class<?>> createTargetClassSet(Aspect aspect) throws Exception {
- Set<Class<?>> targetClassSet = new HashSet<>();
- Class<? extends Annotation> annotation = aspect.value();
- if(annotation != null && annotation.equals((Aspect.class))) {
- for (Class<?> aClass : allClassSet) {
- if(aClass.isAnnotationPresent(annotation)) {
- targetClassSet.add(aClass); // 这里从所有的 class 集合中挑出被 annotation 类型注解的 class 对象集合
- }
- }
- }
- return targetClassSet;
- }
- }
注意: 代码从 1 写到 7, 从 7 到 1 理解有助于了解整体工作流程, 整个用了责任链模式, 模板方法模式, CGLIB 动态代理. 书中叫 Proxy 和 ProxyChain 叫做代理和代理链, 改叫增强和增强链更容易理解, 每一个 Proxy 就是对目标类的方法的一次功能增强.
来源: http://www.bubuko.com/infodetail-3264635.html