AopProxy
新建创建代理的顶层接口AopProxy
package com.xiaoliuliu.six.finger.web.spring.aop; /** * @author 小六六 * @version 1.0 * @date 2020/10/26 17:41 */ public interface AopProxy { Object getProxy(); Object getProxy(ClassLoader classLoader); } 复制代码
Spring选择代理创建逻辑是,如果被代理的类有实现接口用原生JDK的动态代理,否则使用Cglib的动态代理。所以AopProxy有两个子类JdkDynamicAopProxy和CglibAopProxy来实现这两种创建逻辑。
JdkDynamicAopProxy是利用JDK动态代理来创建代理的,因此需实现InvocationHandler接口。
package com.xiaoliuliu.six.finger.web.spring.aop; import com.xiaoliuliu.six.finger.web.spring.aop.intercept.MethodInvocation; import com.xiaoliuliu.six.finger.web.spring.aop.support.AdvisedSupport; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.List; /** * @author 小六六 * @version 1.0 * @date 2020/10/26 17:42 */ public class JdkDynamicAopProxy implements AopProxy, InvocationHandler { private AdvisedSupport advised; public JdkDynamicAopProxy(AdvisedSupport config) { this.advised = config; } @Override public Object getProxy() { return getProxy(this.advised.getTargetClass().getClassLoader()); } @Override public Object getProxy(ClassLoader classLoader) { //JDK的动态代理方式 return Proxy.newProxyInstance(classLoader, this.advised.getTargetClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //获取拦截器链 List<Object> interceptorsAndDynamicMethodMatchers = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, this.advised.getTargetClass()); //外层拦截器,用于控制拦截器链的执行 MethodInvocation invocation = new MethodInvocation( proxy, this.advised.getTarget(), method, args, this.advised.getTargetClass(), interceptorsAndDynamicMethodMatchers ); //开始连接器链的调用 return invocation.proceed(); } } 复制代码
还又我们的cglib也是经常用的
package com.xiaoliuliu.six.finger.web.spring.aop; import com.xiaoliuliu.six.finger.web.spring.aop.intercept.MethodInvocation; import com.xiaoliuliu.six.finger.web.spring.aop.support.AdvisedSupport; 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; /** * @author 小六六 * @version 1.0 * @date 2020/10/12 11:03 * cglib的动态代理 */ public class CglibAopProxy implements AopProxy, MethodInterceptor { private AdvisedSupport advised; public CglibAopProxy(AdvisedSupport config) { this.advised = config; } @Override public Object getProxy() { return getProxy(this.advised.getTargetClass().getClassLoader()); } @Override public Object getProxy(ClassLoader classLoader) { //cglib的方式 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.advised.getTargetClass()); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { //获取拦截器链 List<Object> interceptorsAndDynamicMethodMatchers = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, this.advised.getTargetClass()); //外层拦截器,用于控制拦截器链的执行 MethodInvocation invocation = new MethodInvocation( proxy, this.advised.getTarget(), method, args, this.advised.getTargetClass(), interceptorsAndDynamicMethodMatchers ); //开始连接器链的调用 return invocation.proceed(); } } 复制代码
成员变量AdvisedSupport封装了创建代理所需要的一切资源,从上面的代码就可以看出它至少封装了被代理的目标实例、拦截器链等,实际上它还负责解析AOP配置和创建拦截器。
package com.xiaoliuliu.six.finger.web.spring.aop.support; import com.xiaoliuliu.six.finger.web.spring.aop.aspect.AfterReturningAdviceInterceptor; import com.xiaoliuliu.six.finger.web.spring.aop.aspect.AfterThrowingAdviceInterceptor; import com.xiaoliuliu.six.finger.web.spring.aop.aspect.MethodBeforeAdviceInterceptor; import com.xiaoliuliu.six.finger.web.spring.aop.config.AopConfig; import java.lang.reflect.Method; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @author 小六六 * @version 1.0 * @date 2020/10/26 17:43 */ public class AdvisedSupport { /**被代理的类class*/ private Class<?> targetClass; /**被代理的对象实力*/ private Object target; /**被代理的方法对应的拦截器集合*/ private Map<Method, List<Object>> methodCache; /**AOP外部配置*/ private AopConfig config; /**切点正则表达式*/ private Pattern pointCutClassPattern; public AdvisedSupport(AopConfig config) { this.config = config; } public Class<?> getTargetClass() { return this.targetClass; } public Object getTarget() { return this.target; } /** * 获取拦截器 */ public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) throws Exception { List<Object> cached = methodCache.get(method); if (cached == null) { Method m = targetClass.getMethod(method.getName(), method.getParameterTypes()); cached = methodCache.get(m); this.methodCache.put(m, cached); } return cached; } public void setTargetClass(Class<?> targetClass) { this.targetClass = targetClass; parse(); } /** * 解析AOP配置,创建拦截器 */ private void parse() { //编译切点表达式为正则 String pointCut = config.getPointCut() .replaceAll("\\.", "\\\\.") .replaceAll("\\\\.\\*", ".*") .replaceAll("\\(", "\\\\(") .replaceAll("\\)", "\\\\)"); //pointCut=public .* com.lqb.demo.service..*Service..*(.*) String pointCutForClassRegex = pointCut.substring(0, pointCut.lastIndexOf("\\(") - 4); pointCutClassPattern = Pattern.compile("class " + pointCutForClassRegex.substring( pointCutForClassRegex.lastIndexOf(" ") + 1)); try { //保存切面的所有通知方法 Map<String, Method> aspectMethods = new HashMap<>(); Class aspectClass = Class.forName(this.config.getAspectClass()); for (Method m : aspectClass.getMethods()) { aspectMethods.put(m.getName(), m); } //遍历被代理类的所有方法,为符合切点表达式的方法创建拦截器 methodCache = new HashMap<>(); Pattern pattern = Pattern.compile(pointCut); for (Method m : this.targetClass.getMethods()) { String methodString = m.toString(); //为了能正确匹配这里去除函数签名尾部的throws xxxException if (methodString.contains("throws")) { methodString = methodString.substring(0, methodString.lastIndexOf("throws")).trim(); } Matcher matcher = pattern.matcher(methodString); if (matcher.matches()) { //执行器链 List<Object> advices = new LinkedList<>(); //创建前置拦截器 if (!(null == config.getAspectBefore() || "".equals(config.getAspectBefore()))) { //创建一个Advivce MethodBeforeAdviceInterceptor beforeAdvice = new MethodBeforeAdviceInterceptor( aspectMethods.get(config.getAspectBefore()), aspectClass.newInstance() ); advices.add(beforeAdvice); } //创建后置拦截器 if (!(null == config.getAspectAfter() || "".equals(config.getAspectAfter()))) { AfterReturningAdviceInterceptor returningAdvice = new AfterReturningAdviceInterceptor( aspectMethods.get(config.getAspectAfter()), aspectClass.newInstance() ); advices.add(returningAdvice); } //创建异常拦截器 if (!(null == config.getAspectAfterThrow() || "".equals(config.getAspectAfterThrow()))) { AfterThrowingAdviceInterceptor throwingAdvice = new AfterThrowingAdviceInterceptor( aspectMethods.get(config.getAspectAfterThrow()), aspectClass.newInstance() ); throwingAdvice.setThrowName(config.getAspectAfterThrowingName()); advices.add(throwingAdvice); } //保存被代理方法和执行器链的对应关系 methodCache.put(m, advices); } } } catch (Exception e) { e.printStackTrace(); } } public void setTarget(Object target) { this.target = target; } /** * 判断一个类是否需要被代理 */ public boolean pointCutMatch() { return pointCutClassPattern.matcher(this.targetClass.toString()).matches(); } } 复制代码
AopConfig保存了配置好切面、切点以及通知。
package com.xiaoliuliu.six.finger.web.spring.aop.config; import lombok.Data; /** * @author 小六六 * @version 1.0 * @date 2020/10/26 17:43 */ @Data public class AopConfig { //切点表达式 private String pointCut; //前置通知方法 private String aspectBefore; //后置通知方法 private String aspectAfter; //切面类 private String aspectClass; //异常通知方法 private String aspectAfterThrow; //抛出的异常类型 private String aspectAfterThrowingName; } 复制代码
测试
至于测试的话就是像前面一样,改造一下
网络异常,图片无法展示
|
注入aop就好了。
遇到得问题
其实这边小六六有一个坑,但是自己没搞定,是这样的哈
网络异常,图片无法展示
|
我这个测试类的时候,我们要注入的这个UserServiceImpl 应该是代理对象,但是我们通过动态代理之后生成的代理对象一直是报错的。
网络异常,图片无法展示
|
但是他的拦截器链是成了。但是aop代理对象一直报错。
网络异常,图片无法展示
|
所以那个注入就是一直报空了,老郁闷了,不懂为啥。
结尾
其实spring的aop 说到底就是动态代理+我们各种前中后处理器(责任链模式的实现)。虽然没有完全做出来但是对于spring的aop还是有点帮助的,大家可以参考下。