Imitating the function of spring AOP, we use annotations to build our own framework.

Keywords: Java Junit Spring Lambda

I have been in JAVA pit for more than July, and I also try to build a framework by myself. Recently, I am fascinated by this aspect of spring aop, so I record my current small demo, and I will continue to improve my demo later. I hope that the great gods will not be stingy to teach me.

It mainly uses reflection and java's own proxy class. Theoretical knowledge will not be said, because I am not very clear at present, to avoid misleading, or to avoid talking about it. OK, just follow the code.

Structure:

  

  

Interface 
Person.java
public interface Person {
    void say();
}

 

Interface implementation class

Man.java
public class Man implements Person {
    @Override
    public void say() {
        System.out.println("Man say:....");
    }
}

 

Custom annotation

@interface WaterAOP
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Documented
public @interface WaterAOP {
    enum METHOD{before,after,afterthrowing}
    METHOD method() default METHOD.after;
    String Name() default "Class full name";
}

Custom annotation class

WaterLog.java
public class WaterLog {

    @WaterAOP(Name = "com.water.aop.attempt3.Man",method = WaterAOP.METHOD.after)
    public void afterAction(){
        System.out.println("Postposition behavior");
    }
    @WaterAOP(Name = "com.water.aop.attempt3.Man",method = WaterAOP.METHOD.before)
    public void beforeAction(){
        System.out.println("Preposition behavior");
    }
}

Implement the custom proxy class

The third parameter of the Proxy.newProxyInstance() method does the trick. The lambda expression of java8 is used.

)

  ProxyFactory.java

public class ProxyFactory {
    // Maintain a proxy object that implements the interface,Change to object group after,From the shallower to the deeper
    private Person person;
    private WaterLog waterLog;
    private Method beforeMethod=null,afterMethod=null;
    public ProxyFactory(Person person,WaterLog waterLog){
        this.person=person;
        this.waterLog=waterLog;
    }
    public Object getProxyInstance(){
        return Proxy.newProxyInstance(
                person.getClass().getClassLoader(),
                person.getClass().getInterfaces(),
//                The first parameter is the agent. You can use this parameter if you want to do something to the agent;
//                The second is the method to be implemented,
//                The third is the parameters required to execute the method.
                (Object proxyObj, Method method,Object[] args)->{
                    //If no incoming aop Directly return to null
                    if(waterLog==null){
                        return null;
                    }
                    Class aop=waterLog.getClass();
                    Class c = person.getClass();
                    // Obtain aop Class and assign to some custom variables. The following determines whether there is annotation based on whether these variables have values
                    getAnnotation(aop,c);
                    if(beforeMethod!=null){
                        beforeMethod.invoke(waterLog);
                    }
                    // The proxy object executes the method and gets the return value
                    Object returnValue=method.invoke(person,args);
                    if(afterMethod!=null){
                        afterMethod.invoke(waterLog);
                    }
                    return returnValue;
                }
        );
    }
    private void getAnnotation(Class aop,Class proxy){
        //If there is AOP Class
        if(waterLog!=null){
            // Get all methods of tangent class
            Method[] methodsAOP=aop.getMethods();
            // If the method of the log class to be cut in is not empty
            if(methodsAOP!=null){
                for(Method logMethod:methodsAOP){
                    // Obtain WaterLog Class method WaterAOP annotation
                    WaterAOP waterAOP=logMethod.getAnnotation(WaterAOP.class);
                    if(waterAOP!=null) {
                        // If AOP The annotation on is the same as the class name passed in
                        if (proxy.toString().substring(6).equals(waterAOP.Name())) {
                            if (waterAOP.method() == WaterAOP.METHOD.before) {
                                // assignment ,Later
                                beforeMethod=logMethod;
                            }else if(waterAOP.method() == WaterAOP.METHOD.after){
                                afterMethod=logMethod;
                            }
                        }
                    }
                }
            }
        }
    }

}

Test class

Test.java (junit is a test package, or you can use the main method directly)

public class Test {
    @org.junit.Test
    public void waterAOP(){
        Person person=new Man();
        Person proxyPerson=(Person) new ProxyFactory(person,new WaterLog()).getProxyInstance();
        proxyPerson.say();
    }
}

 

The general process is: pass in the class to be represented and the user-defined annotation class, use reflection to obtain the annotation attribute value of the method in the annotation class, then compare, and then carry out the corresponding operation.

Posted by ksandom on Fri, 10 Apr 2020 07:46:31 -0700