一:前言
还有<aop:before>/<aop:after>/<aop:around>的没有实现,不过根<aop:advisor>是差不多的,就是要额外注册一些东西到AdvisorSupport里,这个等以后有时间再写了;
二:代码
1.Test类,用于描述<aop:pointcut的expression属性,即调用时这个类中声明的方法不会实施aop拦截
package me.silentdoer.aoprealization.action; /** * @author silentdoer * @version 1.0 * @description the description * @date 4/28/18 2:50 PM */ public class Test { public void printSS(){ System.out.println("UXXXXXXXXXXXss"); } }
2.AopTest类,即aspect类(如StudentServiceImpl之类的)
package me.silentdoer.aoprealization.action; /** * @author silentdoer * @version 1.0 * @description 作为pointcut的提供类 * @date 4/27/18 8:14 PM */ public class AopTest extends Test{ public void foo(){ System.out.println("Hello, llll"); System.out.println(foo2(88)); } private String foo2(int num){ System.out.println(String.format("The string is %s", num)); return (num + 100) + ""; } }
3.FooAdviceForAdvisor类,即advisor的实现类
package me.silentdoer.aoprealization.aop.advice; import net.sf.cglib.proxy.MethodProxy; import org.aopalliance.aop.Advice; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import java.lang.reflect.Method; /** * @author silentdoer * @version 1.0 * @description 通过直接实现MethodInterceptor来实现Spring中的<aop:advisor ..></aop:advisor> * @date 4/27/18 8:32 PM */ public class FooAdviceForAdvisor implements MethodInterceptor{ @Override public Object invoke(MethodInvocation methodInvocation) throws Throwable { System.out.println("Before部分"); //System.out.println(methodInvocation.getClass()); Object result = methodInvocation.proceed(); System.out.println("After部分"); return result; } }
4.AopSupport类,实现用户配置和具体产生代理类分离的中间类(around/before/after配置也可以通过这种方式实现)
package me.silentdoer.aoprealization.aop.support; import me.silentdoer.aoprealization.aop.method.DefaultMethodInvocation; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; import java.util.List; /** * @author silentdoer * @version 1.0 * @description 这个类在实际中不允许用户主动使用 * @date 4/28/18 2:53 PM */ public class AopSupport implements MethodInterceptor { private List<Method> pointcuts; private org.aopalliance.intercept.MethodInterceptor advisor; @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { final Method met = method; if (this.pointcuts.stream().anyMatch(m -> m.equals(met))){ DefaultMethodInvocation methodInvocation = new DefaultMethodInvocation(); methodInvocation.setTarget(o); methodInvocation.setMethod(method); // 要通过适配器模式将MethodProxy转换为Method(Method是final无法适配,只好添加MethodProxy属性 methodInvocation.setRealMethod(methodProxy); methodInvocation.setArgs(objects); return advisor.invoke(methodInvocation); }else{ return methodProxy.invokeSuper(o, objects); } } public void setPointcuts(List<Method> pointcuts) { this.pointcuts = pointcuts; } public void setAdvisor(org.aopalliance.intercept.MethodInterceptor advisor){ this.advisor = advisor; } }
5.DefaultMethodInvocation类,用于实现method/args/target的一体化
package me.silentdoer.aoprealization.aop.method; import net.sf.cglib.proxy.MethodProxy; import org.aopalliance.intercept.MethodInvocation; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Method; /** * @author silentdoer * @version 1.0 * @description the description * @date 4/28/18 8:38 PM */ public class DefaultMethodInvocation implements MethodInvocation{ private Method method; private MethodProxy realMethod; private Object[] args; private Object target; @Override public Method getMethod() { return this.method; } @Override public Object[] getArguments() { return this.args; } @Override public Object proceed() throws Throwable { return this.realMethod.invokeSuper(this.target, args); } @Override public Object getThis() { return this.target; } @Override public AccessibleObject getStaticPart() { return this.method; } public void setMethod(Method method) { this.method = method; } public void setArgs(Object[] args) { this.args = args; } public void setTarget(Object target) { this.target = target; //System.out.println(this.target == null); } public void setRealMethod(MethodProxy realMethod) { this.realMethod = realMethod; } }
6.main方法所在类,兼具解析xml和装配代理类的作用(demo主要是为了了解aop的实现原理)
package me.silentdoer.aoprealization; import me.silentdoer.aoprealization.action.AopTest; import me.silentdoer.aoprealization.aop.advice.FooAdviceForAdvisor; import me.silentdoer.aoprealization.aop.support.AopSupport; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; /** * @author silentdoer * @version 1.0 * @description 这里就简单的实现advisor的aop,且expression默认是某个类中所有的declare的方法 * @date 4/27/18 4:56 PM */ public class Entrance { private static Element root; private static AopTest fooBean; public static void main(String[] args) throws DocumentException, ClassNotFoundException, IllegalAccessException, InstantiationException { org.dom4j.io.SAXReader reader = new SAXReader(); ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); Document document = reader.read(classLoader.getResource("aop.xml")); root = document.getRootElement(); List<Element> elements = root.elements(); Class beanClazz = classLoader.loadClass(elements.stream().filter((e) -> e.attributeValue("id").equals("aopTest")).findFirst().get().attributeValue("class")); //System.out.println(beanClazz); //me.silentdoer.aoprealization.action.AopTest // TODO 这个是没有加aop功能时原始的bean,这步可以理解为getBean fooBean = (AopTest) beanClazz.newInstance(); fooBean.foo(); System.out.println("<------------------------------------------------------->"); // TODO 实现BeanFactoryPostProcessor接口的扫描配置文件来为对应的bean组装aop功能 Element config = elements.stream().filter(e -> e.getName().equals("config")).findFirst().get(); parseAopConfig(config); // 动态代理类实现aop功能,但是对于非DeclaredMethod不会做切面拦截处理,比如在Test中的printSS方法; fooBean.foo(); // 实现aop拦截 System.out.println("<---------------------------------------------------------------->"); fooBean.printSS(); // 不符合expression因此即便为fooBean配置了aop对于此方法也不会实施aop功能 } // 根据<aop:config来“重建”需要aop功能的bean,这里就是fooBean private static void parseAopConfig(Element config){ // TODO 这里认定pointcut的expression是获取originBean的所有的DeclaredMethod方法 Element pointcutElem = config.element("pointcut"); List<Method> pointcuts = parsePointcuts(pointcutElem); Element advisorElem = config.element("advisor"); // TODO 这里通过advisorElem得到用户自定义的advisor类对象 FooAdviceForAdvisor advisorBean = getUserAdvisor(advisorElem); // TODO 根据advisor和pointcut组装成一个新的MethodInterceptor对象,这个interceptor是实现了expression和advisor联合的拦截者 MethodInterceptor realInterceptor = parseAdvisor(advisorBean, pointcuts); // TODO 根据配置得知fooBean是需要加上aop功能,因此通过Enhancer重新生成新的bean覆盖老的bean,这步在Spring里是通过实现了BeanFactoryPostProcessor接口的类里执行的 fooBean = (AopTest) Enhancer.create(AopTest.class, realInterceptor); } private static MethodInterceptor parseAdvisor(org.aopalliance.intercept.MethodInterceptor advisor, List<Method> pointcuts){ // 正式情况下AdvisorSupport是包访问权限,而这部分代码也是在和此类同一个包里面实现的因此AdvisorSupport是系统组件不由用户手动创建 AopSupport result = new AopSupport(); result.setAdvisor(advisor); result.setPointcuts(pointcuts); return result; } private static List<Method> parsePointcuts(Element aopPointcut){ // TODO 本来应该通过aopPointcut的expression来获取,不过这个主要是实现aop对表达式的解析忽略 return Arrays.asList(AopTest.class.getDeclaredMethods()); } // 根据advisor-ref获取advisor对象 private static FooAdviceForAdvisor getUserAdvisor(Element advisor){ FooAdviceForAdvisor result = new FooAdviceForAdvisor(); return result; } }
7.aop.xml配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:aop="silentdoer"> <!-- 模拟注册到Spring里管理,这里则只是简单的通过dom4j来搜索 --> <bean id="aopTest" class="me.silentdoer.aoprealization.action.AopTest"/> <bean id="fooAdvisor" class="me.silentdoer.aoprealization.aop.advice.FooAdviceForAdvisor"/> <aop:config> <!-- 这里暂且认为me.silentdoer.aoprealization.action.AopTest.*就是AopTest中所有Declared的方法 --> <aop:poincut id="pointcut1" expression="me.silentdoer.aoprealization.action.AopTest.*"/> <aop:advisor advisor-ref="fooAdvisor" poincut-ref="pointcut1"/> </aop:config> <!--<bean id="fooAdvice" class="me.silentdoer.aoprealization.aop.advice.FooAdvice"/> <aop:config> <aop:pointcut id="pointcut2" expression="me.silentdoer.aoprealization.action.AopTest.*"/> <aop:aspect ref="fooAdvice"> <aop:around method="around" poincut-ref="poincut2"/> </aop:aspect> </aop:config>--> </beans>