spring AOP 3: Use @AspectJ to define the entry point

The use of annotations to create aspects is a key feature introduced by AspectJ 5. Before AspectJ 5, writing AspectJ aspects requires learning an extension of the Java language, but AspectJ's annotation-oriented model can easily convert any class into aspects through a small number of annotations.

AspectJ provides five annotations to define notifications, as shown in Table 4.2:

Table 4.2 Spring uses AspectJ annotations to declare notification methods

Example 1: Audience class: a section to watch the performance

 

package com.dxz.aop.demo7;

import org.springframework.stereotype.Component;

@Component
public class Performance {

    public void perform(){
        System.out.println("我是男一号,我正在表演");
    }
}
package com.dxz.aop.demo7;

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.context.annotation.Configuration;

@Aspect
@Configuration
public class Audience {

    /**
     * 手机调至静音状态
     */
    @Before("execution(** com.dxz.aop.demo7.Performance.perform(..))")
    public void silenceCellPhones() {
        System.out.println("silence cell phones");
    }
    
    /**
     * 就坐
     */
    @Before("execution(** com.dxz.aop.demo7.Performance.perform(..))")
    public void takeSeats() {
        System.out.println("taking seats");
    }
    
    /**
     * 鼓掌喝彩
     */
    @AfterReturning("execution(** com.dxz.aop.demo7.Performance.perform(..))")
    public void applause() {
        System.out.println("CLAP CLAP CLAP!");
    }
    
    /**
     * 退款
     */
    @AfterReturning("execution(** com.dxz.aop.demo7.Performance.perform(..))")
    public void demandRefund() {
        System.out.println("demanding a refund");
    }
}
package com.dxz.aop.demo7;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Import;

@Configuration
@ComponentScan
@EnableAspectJAutoProxy
@Import({Audience.class})/*@Aspect可以生效,相当于Configuration类作用,都是配置类*/  
public class AppConfig {

}

Start class: 

package com.dxz.aop.demo7;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test7 {

    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        Performance outPut = (Performance) context.getBean("performance");
        outPut.perform();
    }
}

result: 

 

You may have noticed that all these annotations are given a pointcut expression as its value, and at the same time, the pointcut expressions of the four methods are the same. In fact, they can be set to different pointcut expressions, but here, this pointcut expression can meet the needs of all notification methods. This repetition makes people feel something is wrong. If we only define this pointcut once and then quote it every time we need it, then this would be a good solution.

Fortunately, we can do exactly this: @Pointcut annotation can define reusable pointcuts within a @AspectJ cut plane. The next program in Listing 4.2 shows the new Audience, which now uses @Pointcut.

Example 2: @Pointcut annotation declares frequently used pointcut expressions

package com.dxz.aop.demo7;

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.Configuration;

@Aspect
@Configuration
public class Audience2 {

    @Pointcut("execution(** com.dxz.aop.demo7.Performance.perform(..))")
    public void performance() {}
    
    /**
     * 手机调至静音状态
     */
    @Before("performance()")
    public void silenceCellPhones() {
        System.out.println("silence cell phones");
    }
    
    /**
     * 就坐
     */
    @Before("performance()")
    public void takeSeats() {
        System.out.println("taking seats");
    }
    
    /**
     * 鼓掌喝彩
     */
    @AfterReturning("performance()")
    public void applause() {
        System.out.println("CLAP CLAP CLAP!");
    }
    
    /**
     * 退款
     */
    @AfterReturning("performance()")
    public void demandRefund() {
        System.out.println("demanding a refund");
    }
}
package com.dxz.aop.demo7;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Import;

@Configuration
@ComponentScan
@EnableAspectJAutoProxy
@Import({Audience2.class})/*@Aspect可以生效,相当于Configuration类作用,都是配置类*/  
public class AppConfig {

}

Results and examples are equally effective

Around advice

Example 3: We use a surround notification to replace multiple different pre-notifications and post-notifications

package com.dxz.aop.demo7;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.Configuration;

@Aspect
@Configuration
public class Audience3 {

    @Pointcut("execution(** com.dxz.aop.demo7.Performance.perform(..))") //定义命名额切点
    public void performance() {
    }

    @Around("performance()") //环绕通知方法
    public void watchPerformance(ProceedingJoinPoint jp) {
        try {
            System.out.println("silence cell phones");
            System.out.println("taking seats");
            jp.proceed();
            System.out.println("CLAP CLAP CLAP!");
            System.out.println("demanding a refund");
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
}
package com.dxz.aop.demo7;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Import;

@Configuration
@ComponentScan
@EnableAspectJAutoProxy
@Import({Audience3.class})/*@Aspect可以生效,相当于Configuration类作用,都是配置类*/  
public class AppConfig {

}

Other unchanged, the operation result is the same as above

For the word Introduction, I personally think that it is most appropriate to understand the introduction. The goal is to introduce a new interface to an existing class (one may ask: What is the use? Simply put, you can transform the current object into Another object, then obviously, you can call the method of another object), see an example to understand.  

Suppose that there is already a UserService class that provides the service of saving User objects, but now I want to add the function of verifying User. Only the verified User is provided with a save service. It can be solved by Introduction without modifying the UserService class code .

Define an interface named Skill and its implementation class SkillImpl. We are going to add the getSkill () method of SkillImpl to other class instances

package com.dxz.aop.demo8;

public interface Person {
    public void sayIdentification();
}
package com.dxz.aop.demo8;

import org.springframework.stereotype.Component;

@Component
public class Student implements Person {

    public void sayIdentification() {
        System.out.println("hello world!");
        
    }

}

Additional functions 

package com.dxz.aop.demo8;

import org.springframework.stereotype.Component;

@Component
public interface Skill {
    void getSkill(String skill);
}

package com.dxz.aop.demo8;

import org.springframework.stereotype.Component;

@Component
public class SkillImpl implements Skill {

    public void getSkill(String skill) {
        System.out.println(skill);
    }
    
}

SpringAop configuration class 

package com.dxz.aop.demo8;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AopConfig {

    // “...demo8.Perso”后面的 “+” 号,表示只要是Person及其子类都可以添加新的方法
    @DeclareParents(value = "com.dxz.aop.demo8.Person+", defaultImpl = SkillImpl.class)
    public Skill skill;
}

SpringConfig configuration class 

package com.dxz.aop.demo8;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@ComponentScan
@Configuration
@EnableAspectJAutoProxy
public class SpringConfig {
}

Test 

package com.dxz.aop.demo8;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class AopTest {

    @Autowired
    private Student student;

    @Test
    public void test(){
        Skill skill = (Skill)student; // 通过类型转换,student对象就拥有了SkillImp 类的方法
        skill.getSkill("我会英语");
        student.sayIdentification();
    }
}

 result:

 

Published 203 original articles · won praise 6 · views 4505

Guess you like

Origin blog.csdn.net/weixin_42073629/article/details/105212389
Recommended