SpringAOP entry point of use to create notification

Having said that several types of notifications SpringAOP and how to create a simple notification , see address

First, what is the starting point

By the previous example, we can create ProxyFactory way to create a notification, then get a target class. Through different types of notifications you can do different things on these methods. However, all the methods in this way will have a role in the whole class, but a lot of time on the part of the method we want this class notification process, it would be used to precisely control the entry point to a specific method

  • In other words, our starting point is the method used to determine a class (the exact method), similar to the definition of some rules, and to find the rule to match the class, know this, look down much easier a.

Second, the entry point of classification

When you want to create an entry point in the Spring, will be realized Pointcut class.

package org.springframework.aop;

public interface Pointcut{
    ClassFilter getClassFilter();
    MethodMatcher getMethodMacher();
}

Two or more class method returns the following source code:

  • ClassFilter
package org.springframework.aop;
/**
*   这是一个函数式接口,就是传入一个类,
*   如果这个类满足我们的要求,就返回true
*   也就是说这个切入点适用于这个类(也就是这个类不匹配我们的规则)
*/
@FunctionalInterface
public interface ClassFilter {
    boolean matches(Class<?> var1);
}
  • MethodMatcher
package org.springframework.aop;

import java.lang.reflect.Method;
/**
*   这个当然就是用来匹配方法了,
*   有两种类型,动态和静态,这个由isRuntime()的返回值来决定,true就是动态,false就是静态。这个类型就是决定了这个切入点是动态的还是静态的
*   
*/
public interface MethodMatcher {
    MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
    //用于静态匹配,就是和方法的参数无关
    boolean matches(Method var1, Class<?> var2);

    boolean isRuntime();
    //用于动态匹配,也就是和方法的参数有关,因为参数是会变的
    boolean matches(Method var1, Class<?> var2, Object... var3);
}

In summary, the starting point is divided into two types, static and dynamic entry point entry point, entry point to each argument dynamic inspection method is not meet the requirements, which will result in additional expenses. If you can, if you can, try to use a static entry point.

Third, the entry point of the eight implementation class

Implementation class description
org.springframework.aop.support.annotation.AnnotationMatchingPointcut Find specific notes on a class or method, you need JDK5 above
org.springframework.aop.aspectj.AspectJExpressionPointcut AspectJ weaver used to assess AspectJ pointcut syntax statement of formula
org.springframework.aop.support.ComposablePointcut Using two or more entry points such as a union () and intersection () operation and the like in combination
org.springframework.aop.support.ControlFlowPointcut Is a special entry point, which matches all another method of controlling a flow method, i.e., as a result of any of the methods of another method called directly or indirectly
org.springframework.aop.support.JdkRegexpMethodPointcut Method name using regular expressions define the starting point for more than JDK4
org.springframework.aop.support.NameMatchMethodPointcut As the name suggests, this is a simple method of matching a list of names
org.springframework.aop.support.DynamicMethodMatcherPointcut The class as a base class to create a dynamic entry point
org.springframework.aop.support.StaticMethodMatcherPointcut As an entry point to create a position of the base class

Fourth, the use StaticMethodMatcherPointcut to create a static entry point

  • Create a class, the two methods. Our goal is to only walk () method to create around advice, print one, "I am a cute cat."
public class Cat {
    public void sleep(){
        System.out.println("sleep....");
    }
    public void walk(){
        System.out.println("walking....");
    }
}
  • Creating an entry point
public class MethodPointcutDemo extends StaticMethodMatcherPointcut {

    @Override
    public boolean matches(Method method, Class<?> aClass) {
        return method.getName().equals("walk");
    }

    @Override
    public ClassFilter getClassFilter() {
        return clz -> clz == Cat.class;
        
//        上边的lambda表达式等于下边的这个
//        return new ClassFilter() {
//            @Override
//            public boolean matches(Class<?> clz) {
//                return clz == Cat.class;
//            }
//        };
    }
}

Top of the lambda expression can be viewed https://www.cnblogs.com/Lyn4ever/p/11967959.html , just write lambda expressions arise when behind, and are not described

In this method the top, of course, we can not achieve getClassFilter () method, because this method has been implemented through a higher level, we can go directly to the judge in this class is not Cat.class matches method

  • Notification class (this is the same as the previous one, creating a surround notification)
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class CatAdvisor implements MethodInterceptor{

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        //最不靠谱的方法,我们可以在这里判断这个method的是不是walk,从而要不要进行通知
        System.out.println("I am a cute Cat.");
        Object proceed = invocation.proceed();
        return proceed;
    }
}

Of course, here we can also determine the method and class names, why use an entry point yet. But this does not fly, we need to realize here in our logic code, which is controlled through an entry point class, which methods to be informed, which is more flexible.

  • testing method
public static void main(String[] args) {
        Cat cat = new Cat();

        Pointcut pointcut = new MethodPointcutDemo();//切入点实例
        Advice advice = new CatAdvisor();//通知类实例(就是我们的通知代码存放的类的对象)

        Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);//切面类,就是切入点和通知类的集合

        ProxyFactory proxyFactory = new ProxyFactory();
        //和之前代码的区别就是这一句,这里我们使用的是切入点控制,如果把这句注释了,就要用设置通知类
        proxyFactory.addAdvisor(advisor);//设置切面类,包含切入点(控制通知点)和通知类(逻辑代码)
        
        //如果注释了上面一句,用这一句的话,就会对这个类中的所有方法都通知
//        proxyFactory.addAdvice(advice);//设置通知类
        proxyFactory.setTarget(cat);
        Cat proxy = (Cat) proxyFactory.getProxy();

        proxy.sleep();
        proxy.walk();
    }

Operating results affirm what we want it

sleep....
I am a cute Cat.
walking....

Fifth, use DyanmicMatcherPointcut create a dynamic entry point

The top and static entry point is the same, but the parameters passed to the method is to allow time to meet certain requirements, notification will be performed. Due to space reasons, I do not write, you can download the code at the end of this article to read.

Six, PointCut other types of implementation class

1. A simple name matching ( NameMatchMethodPointcut )

Target class or classes before and notification of the Cat class, the entry point before the implementation class do not write, because this class has done a default implementation, interested can look at its source code, very simple, is to match the class name, and we just created a static entry point almost.

public class NameMatchPointcutDemo {
    public static void main(String[] args) {
        Cat cat = new Cat();

        //这个类已经是个实现类,我们就不需要再去写实现类了
        NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
        pointcut.addMethodName("walk");

        Advisor advisor = new DefaultPointcutAdvisor(pointcut,new CatAdvisor());

        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.addAdvisor(advisor);
        proxyFactory.setTarget(cat);
        Cat proxy = (Cat) proxyFactory.getProxy();

        proxy.sleep();
        proxy.walk();
    }
}

2. Use a regular expression to create an entry point ( JdkRegexpMethodPointcut )

Just write the test class, and the other are the same top

public class JdkRegexpPointcutDemo {

    public static void main(String[] args) {
        Cat cat = new Cat();

        JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
        pointcut.setPattern(".*ee.*");//匹配中间有ee字母的,sleep()

        Advisor advisor = new DefaultPointcutAdvisor(pointcut,new CatAdvisor());

        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.addAdvisor(advisor);
        proxyFactory.setTarget(cat);
        Cat proxy = (Cat) proxyFactory.getProxy();

        proxy.sleep();
        proxy.walk();
    }
}

3. Use AspectJ pointcut expression to create an entry point ( AspectJExpressionPointcut )

To join its dependencies when using AspectJ

    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>1.9.1</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.1</version>
    </dependency>
public class AspectJExpressionPointcutDemo {
    public static void main(String[] args) {
        Cat cat = new Cat();

        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("execution(* walk*(..))");

        Advisor advisor = new DefaultPointcutAdvisor(pointcut, new CatAdvisor());

        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.addAdvisor(advisor);
        proxyFactory.setTarget(cat);
        Cat proxy = (Cat) proxyFactory.getProxy();

        proxy.sleep();
        proxy.walk();
    }
}

This means that the execution of the expression: Any beginning of the walk, having any parameters and return values ​​in any method

4. Create annotations matching entry point ( AnnotationMatchingPointcut )

First, a custom annotation, if not really understand, reference Java custom class notes, and use of them

/**
 * 这个注解是用于运行时期、可用于类、方法上
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface MyAdvice {
}

Then add (like to be notified) the notes on the target method

    /**
     * 为了不与之前的冲突,就新写了一个方法
     */
    @MyAdvice
    public void eat(){
        System.out.println("eating....");
    }

And then specify the name of the comment in the main method:

public class AnnotationPointcutDemo {
    public static void main(String[] args) {
        Cat cat = new Cat();

        AnnotationMatchingPointcut pointcut = AnnotationMatchingPointcut
                .forMethodAnnotation(MyAdvice.class);
        //这个类还有一个.forClassAnnotation()方法,就是指定类的

        Advisor advisor = new DefaultPointcutAdvisor(pointcut, new CatAdvisor());

        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.addAdvisor(advisor);
        proxyFactory.setTarget(cat);
        Cat proxy = (Cat) proxyFactory.getProxy();

        proxy.sleep();//不会被通知
        proxy.walk();//不会被通知
        proxy.eat();//会被通知
    }
}

Code has been uploaded to github, if you like, give a star

Previous: SpringAOP basis

Guess you like

Origin www.cnblogs.com/Lyn4ever/p/Lyn4ever.html