• 利用cglib包实现Spring中aop的<aop:advisor>功能


    一:前言

      还有<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>
  • 相关阅读:
    Cannot find a free socket for the debugger
    maven自己创建jar坐标(比如oracle驱动包)
    svn“Previous operation has not finished; run 'cleanup' if it was interrupted“报错的解决方法
    java发http请求
    Spring MVC
    函数节流 防抖
    js 执行顺序
    铺平多维对象数组 js
    vue 线上图标404
    vue-devtools--------vue浏览器工具
  • 原文地址:https://www.cnblogs.com/silentdoer/p/8968206.html
Copyright © 2020-2023  润新知