Use the cglib package to implement the <aop:advisor> function of aop in Spring

I. Introduction

  There is also no implementation of <aop:before>/<aop:after>/<aop:around>, but the root <aop:advisor> is similar, that is, some additional things need to be registered in AdvisorSupport, which will be added later when there is time. wrote;

Two: code

1. The Test class is used to describe the expression attribute of <aop:pointcut, that is, the method declared in this class will not implement aop interception when called

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 class, that is aspect class (such as StudentServiceImpl and the like)

package me.silentdoer.aoprealization.action;

/**
 * @author silentdoer
 * @version 1.0
 * @description as the provided class for 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 class, the implementation class of 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 implements <aop:advisor ..></aop:advisor> in Spring by directly implementing MethodInterceptor
 * @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 part" ); // You can add your own before function here
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println("After部分");
        return result;
    }
}

4.AopSupport class, an intermediate class that separates user configuration and specific generation of proxy classes (around/before/after configuration can also be implemented in this way)

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 This class does not allow users to actively use it in practice
 * @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. The class where the main method is located has the functions of parsing xml and assembling proxy classes (demo is mainly to understand the implementation principle of 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 here simply implements advisor's aop, and expression defaults to all declare methods in a class
 * @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 This is the original bean without aop function, this step can be understood as getBean 
        fooBean = (AopTest) beanClazz.newInstance();
        fooBean.foo();

        System.out.println("<------------------------------------------------------->");

        // TODO implements the scanning configuration file of the BeanFactoryPostProcessor interface to assemble the aop function for the corresponding bean 
        Element config = elements.stream().filter(e -> e.getName().equals("config" )).findFirst(). get();
        parseAopConfig(config);
        // The dynamic proxy class implements the aop function, but will not intercept the aspect for non-DeclaredMethod, such as the printSS method in Test; fooBean.foo 
        ();   // implement aop interception 
        System.out.println("<--- -------------------------------------------------- ------------->" );
        fooBean.printSS();   // does not conform to expression, so even if aop is configured for fooBean, the aop function will not be implemented for this method 
    }

    // According to <aop:config to "rebuild" the bean that needs aop function, here is fooBean 
    private  static  void parseAopConfig(Element config){
         // TODO here determines that the expression of pointcut is to obtain all the DeclaredMethod methods of originBean. 
        Element pointcutElem = config. element("pointcut" );
        List<Method> pointcuts = parsePointcuts(pointcutElem);
        Element advisorElem = config.element("advisor" );
         // TODO here gets the user-defined advisor class object 
        FooAdviceForAdvisor advisorBean = getUserAdvisor(advisorElem);
         // TODO is assembled into a new MethodInterceptor object according to advisor and pointcut, this The interceptor is an interceptor that implements the combination of expression and advisor. 
        MethodInterceptor realInterceptor = parseAdvisor(advisorBean, pointcuts);
         // TODO knows that fooBean needs to add aop function according to the configuration, so the new bean is regenerated through the Enhancer to cover the old bean. The first step in Spring is to execute fooBean in a class that implements the BeanFactoryPostProcessor interface 
        = (AopTest) Enhancer.create(AopTest.class , realInterceptor);
    }

    private  static MethodInterceptor parseAdvisor(MethodInterceptor advisor, List<Method> pointcuts){
         // Officially, AdvisorSupport is a package access permission, and this part of the code is also implemented in the same package as this class, so AdvisorSupport is a system component that is not manually created by the user 
        AopSupport result = new AopSupport();
        result.setAdvisor(advisor);
        result.setPointcuts(pointcuts);
        return result;
    }

    private  static List<Method> parsePointcuts(Element aopPointcut){
         // TODO should have been obtained through the expression of aopPointcut, but this is mainly to implement aop's parsing of expressions and ignore 
        return Arrays.asList(AopTest.class .getDeclaredMethods ());
    }

    // Get the advisor object according to advisor-ref 
    private  static FooAdviceForAdvisor getUserAdvisor(Element advisor){
        FooAdviceForAdvisor result = new FooAdviceForAdvisor();
        return result;
    }
}

6.aop.xml configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:aop="silentdoer">

    <!-- Simulated registration is managed in Spring, here is just a simple search through 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>

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325003789&siteId=291194637