AOP-Spring实现方式

AOP不是Spring框架特有的,Spring只是支持AOP编程的框架之一。而SpringAOP是一种基于方法拦截的AOP(有些AOP能够对方法的参数进行拦截)。

下文主要介绍使用注解方式@AspectJ实现AOP的拦截功能(还有不常用的XML配置方式)。

 

被拦截的对象接口:RoleService.java

public interface RoleService {
    void printRole(Role role);
}

 

被拦截的对象实现类:RoleServiceImpl.java。printRole()为连接点。

@Component
public class RoleServiceImpl implements RoleService {
    public void printRole(Role role) {
        System.out.println("打印用户信息:用户id:" + role.getId() + ";用户名称:" + role.getName() + ";用户备注:" + role.getNote());
    }
}

 

切面类:RoleAspect.java。

切面类对于动态代理概念而言,如同一个‘拦截器’。在Spring中只要使用@Aspect注解了一个类,那么SpringIOC容器就会认为这是一个切面了。

spring通过execution里的正则表达式判断是否需要拦截你的方法。

@Aspect
public class RoleAspect {

    // execution:代表方法执行时会触发;*:代表任意返回类型;类的全限定名;(..):任意的参数
    @Pointcut("execution(* com.xxx.service.impl.RoleServiceImpl.printRole(..))")
    public void print() {}

    @Before("print()")
    public void before() {
        System.out.println("before...");
    }

    @After("print()")
    public void after() {
        System.out.println("after...");
    }

    @AfterReturning("print()")
    public void afterReturning() {
        System.out.println("afterReturning...");
    }

    @AfterThrowing("print()")
    public void afterThrowing() {
        System.out.println("afterThrowing...");
    }

    @Around("print()")
    public void around(ProceedingJoinPoint pjp) {
        System.out.println("around before......");
        try {
            pjp.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("around after......");
    }
}

 

测试AOP:

配置SpringBean:AopConfig.java

@Configuration
@EnableAspectJAutoProxy  // 启用AspectJ框架的自动代理,这个时候Spring才会自动生成动态代理对象
@ComponentScan("com.ssm.chapter11.game")
public class AopConfig {
    @Bean
    public RoleAspect getRoleAspect() {
        return new RoleAspect();  // 生成一个切面实例
    }
}

main入口:Main.java

public class Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(AopConfig.class);
        RoleService roleService = ctx.getBean(RoleService.class); 
        Role role = new Role(1L, "role_name_1", "note_1");
        roleService.printRole(role);
    }
}

 

SpringAOP原则:
当类存在实现接口时,Spring提供JDK动态代理,从而织入各种通知。若不存在,采用CGLIB动态代理。

各概念:

目标对象:target。被通知/横切的对象。

代理:proxy。切面、通知、目标混合之后的对象。

连接点:joinpoint。目标对象上所定义的被pointcut过滤后的方法。通知要插入代码的具体位置。上述代码中的printRole()方法就是joinpoint。
切入点:pointcut。AOP通过pointcut定位到特定的joinpoint。例上述代码中的:execution(* com.xxx.service.impl.RoleServiceImpl.printRole(..))。

通知:advice。某个具体的joinpoint采取的行为。切面对象完成的工作(非业务代码),即对切入点增强的内容。例上述代码中的:System.out.println("xxx ....")。

通知器:advisor。由一个pointcut和一个advice组成。例上述代码中:@Before("print()") public void before(){...........}。一个方法表示一个通知器。

切面:aspect。pointcut+advice。上例中的:RoleAspect.java切面类。

织入:weaving。把增强代码应用到目标上,生成代理对象的过程。

 

通知advice分类

before:            通知方法 在目标方法 调用前 执行;

after:               通知方法 在目标方法 返回或异常后 执行;

after-returning:通知方法 在目标方法 返回后 执行;

after-throwing:通知方法 在目标方法 抛出异常后 执行;

around:           通知方法 将目标方法 封装起来;

 

织入weaving时期

编译期:切面在目标类编译时被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的。

类加载期:切面在目标类加载到JVM时被织入。这种方式需要特殊的类加载器。它可以在目标类引入应用之前引入增强目标类的字节码。

运行期:切面在应用运行的某个时期被织入。一般情况下,在织入切面时,AOP容器就会为目标对象动态创建一个代理对象。SpringAOP采用的就是这种。

 

posted @ 2023-11-21 15:37  DoubleFishes  阅读(7)  评论(0编辑  收藏  举报