利用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.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

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 intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Before部分");  // 这里可以添加自己的before功能
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println("After部分");
        return result;
    }
}

4.AopSupport类,实现用户配置和具体产生代理类分离的中间类(around/before/after配置也可以通过这种方式实现)

package me.silentdoer.aoprealization.aop.support;

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 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))){
            return advisor.intercept(o, method, objects, methodProxy);
        }else{
            return methodProxy.invokeSuper(o, objects);
        }
    }

    public void setPointcuts(List<Method> pointcuts) {
        this.pointcuts = pointcuts;
    }

    public void setAdvisor(MethodInterceptor advisor){
        this.advisor = advisor;
    }

}

5.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(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;
    }
}

6.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>

猜你喜欢

转载自www.cnblogs.com/silentdoer/p/8968206.html