zoukankan      html  css  js  c++  java
  • spring 使用@AspectJ注解开发Spring AOP

     选择切点

      Spring是方法级别的AOP框架,而我们主要也是以某个类的某个方法作为切点,用动态代理的理论来说,就是要拦截哪个方法织入对应AOP通知。
      代码清单:打印角色接口
    package com.ssm.chapter11.aop.service;
    
    import com.ssm.chapter11.game.pojo.Role;
    
    public interface RoleService {
    
        // public void printRole(Role role);
    
        public void printRole(Role role, int sort);
    
    }
      代码清单:RoleService实现类
    package com.ssm.chapter11.aop.service.impl;
    
    import org.springframework.stereotype.Component;
    import com.ssm.chapter11.aop.service.RoleService;
    import com.ssm.chapter11.game.pojo.Role;
    
    @Component
    public class RoleServiceImpl implements RoleService {
    
        // @Override
        // public void printRole(Role role) {
        //     System.out.println("{id: " + role.getId() + ", " + "role_name : " + role.getRoleName() + ", " + "note : " + role.getNote() + "}");
        // }
    
        public void printRole(Role role, int sort) {
            System.out.println("{id: " + role.getId() + ", " + "role_name : " + role.getRoleName() + ", " + "note : " + role.getNote() + "}");
            System.out.println(sort);
        }
    
    }
      这个类没什么特别的,只是这个时候如果把printRole作为AOP的切点,那么用动态代理的语言就是要为类RoleServi-ceImpl生成代理对象,然后拦截printRole方法,于是可以产生各种AOP通知方法。

    创建切面

      选择好了切点就可以创建切面了,对于动态代理的概念而言,它就如同一个拦截器,在Spring中只要使用@Aspect注解一个类,那么Spring IoC容器就会认为这是一个切面了
    package com.ssm.chapter11.aop.aspect;
    
    import com.ssm.chapter11.aop.verifier.RoleVerifier;
    import com.ssm.chapter11.aop.verifier.impl.RoleVerifierImpl;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    
    @Aspect
    public class RoleAspect {
    
        @DeclareParents(value = "com.ssm.chapter11.aop.service.impl.RoleServiceImpl+", defaultImpl = RoleVerifierImpl.class)
        public RoleVerifier roleVerifier;
    
        @Pointcut("execution(* com.ssm.chapter11.aop.service.impl.RoleServiceImpl.printRole(..))")
        public void print() {
        }
    
        // @Before("execution(* com.ssm.chapter11.aop.service.impl.RoleServiceImpl.printRole(..))")
        // @Before("execution(* com.ssm.chapter11.*.*.*.*.printRole(..)) && within(com.ssm.chapter11.aop.service.impl.*)")
        @Before("print()")
        // @Before("execution(* com.ssm.chapter11.aop.service.impl.RoleServiceImpl.printRole(..)) && args(role, sort)")
        public void before() {
            System.out.println("before ....");
        }
    
        @After("execution(* com.ssm.chapter11.aop.service.impl.RoleServiceImpl.printRole(..))")
        public void after() {
            System.out.println("after ....");
        }
    
        @AfterReturning("execution(* com.ssm.chapter11.aop.service.impl.RoleServiceImpl.printRole(..))")
        public void afterReturning() {
            System.out.println("afterReturning ....");
        }
    
        @AfterThrowing("execution(* com.ssm.chapter11.aop.service.impl.RoleServiceImpl.printRole(..))")
        public void afterThrowing() {
            System.out.println("afterThrowing ....");
        }
    
        @Around("print()")
        public void around(ProceedingJoinPoint jp) {
            System.out.println("around before ....");
            try {
                jp.proceed();
            } catch (Throwable e) {
                e.printStackTrace();
            }
            System.out.println("around after ....");
        }
    
    }

    连接点

      Spring是如何判断是否需要拦截方法的,毕竟并不是所有的方法都需要使用AOP编程,这就是一个连接点的问题。在注解中定义了execution的正则表达式,Spring是通过这个正则表达式判断是否需要拦截你的方法的,这个表达式是:
      execution(* com.ssm.chapter11.aop.service.impl.RoleServiceImpl.printRole(..))
      依次对这个表达式做出分析。
      •execution:代表执行方法的时候会触发。
      •*:代表任意返回类型的方法。
      •com.ssm.chapter11.aop.service.impl.RoleServiceImpl:代表类的全限定名。
      •printRole:被拦截方法名称。
      •(..):任意的参数。
      显然通过上面的描述,全限定名为com.ssm.chapter11.aop.service.impl.RoleServiceImpl的类的printRole方法被拦截了,这样它就按照AOP通知的规则把方法织入流程中。


    测试AOP

      代码清单:配置Spring bean
    package com.ssm.chapter11.aop.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;
    import com.ssm.chapter11.aop.aspect.RoleAspect;
    
    @Configuration
    @EnableAspectJAutoProxy
    @ComponentScan("com.ssm.chapter11.aop")
    public class AopConfig {
    
        @Bean
        public RoleAspect getRoleAspect() {
            return new RoleAspect();
        }
    
    }
      Spring还提供了XML的方式,这里就需要使用AOP的命名空间了
    <?xml version='1.0' encoding='UTF-8' ?>
    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
            http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
    
        <aop:aspectj-autoproxy/>
        <bean id="roleAspect" class="com.ssm.chapter11.aop.aspect.RoleAspect"/>
        <bean id="roleService" class="com.ssm.chapter11.aop.service.impl.RoleServiceImpl"/>
    
    </beans>
      无论用XML还是用Java的配置,都能使Spring产生动态代理对象,从而组织切面,把各类通知织入到流程当中

      代码清单:测试AOP流程
    package com.ssm.chapter11.aop.main;
    
    import com.ssm.chapter11.aop.verifier.RoleVerifier;
    import com.ssm.chapter11.aop.verifier.impl.RoleVerifierImpl;
    import org.aspectj.lang.annotation.DeclareParents;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import com.ssm.chapter11.aop.config.AopConfig;
    import com.ssm.chapter11.aop.service.RoleService;
    import com.ssm.chapter11.game.pojo.Role;
    
    public class Main {
    
        public static void main(String[] args) {
    
            ApplicationContext ctx = new AnnotationConfigApplicationContext(AopConfig.class);
            // 使用XML使用ClassPathXmlApplicationContext作为IoC容器
            // ApplicationContext ctx = new ClassPathXmlApplicationContext("ssm/chapter11/spring-cfg3.xml");
            RoleService roleService = ctx.getBean(RoleService.class);
    
            Role role = new Role();
            role.setId(1L);
            role.setRoleName("role_name_1");
            role.setNote("note_1");
    
            RoleVerifier roleVerifier = (RoleVerifier) roleService;
            if (roleVerifier.verify(role)) {
                roleService.printRole(role, 1);
            }
            System.out.println("####################");
            //测试异常通知
            // role = null;
            // roleService.printRole(role);
        }
    
    }



  • 相关阅读:
    xxx
    04消息队列zmq的发布者-订阅者的计算π的简单程序。
    03网络编程从之异步服务器
    03Python网络编程之多线程服务端。
    03Python网络编程之单线程服务端
    03Python网络编程之客户端。
    03Python网络编程系列之服务端
    02select监听客户端
    02select监听服务端
    07爬虫之-urllib总结
  • 原文地址:https://www.cnblogs.com/ooo0/p/11018740.html
Copyright © 2011-2022 走看看