zoukankan      html  css  js  c++  java
  • 面向切面编程(三)

    使用@AspectJ注解开发Spring AOP

    1.选择连接点(join point)

    spring是方法级别的AOP框架,而我们主要也是以某个类的某个方法作为连接点,用动态代理的理论来说,就是要拦截某个方法织入对应AOP通知。

    public interface RoleService {
        
        public void printRole(Role role);
    }
    
    @Component
    public class RoleServiceImpl implements RoleService {
    
        @Override
        public void printRole(Role role) {
            // TODO Auto-generated method stub
            System.out.println("{id="+role.getId()+",roleName="+role.getRoleName()+",note="+role.getNote()+"}");
        }
    
    }

    printRole方法作为AOP的连接点。用动态代理来说就是要为类RoleServiceImpl生成代理对象,然后拦截printRole方法,于是可以产生各种AOP通知方法。

    2.创建切面

    选择好连接点就可以创建切面了,用动态代理来说,它就如同一个拦截器。在Spring中用@Aspect注解一个类,IOC容器就会认为这是一个切面了。

    @Aspect
    public class RoleAspect {
        @Pointcut("execution(* test1.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....");
        }
    }

    @Pointcut定义一个切点。

    4.测试AOP

    //这个类是对Spring的Bean进行配置,采用的是注解方式
    //表明这是个配置类,相当于xml文件
    @Configuration
    //开启动态代理,开启AOP
    @EnableAspectJAutoProxy
    //扫描这个包下的所有bean
    @ComponentScan("test1")
    public class AopConfig {
        //表示创建一个bean,返回值类型表示bean的类型,方法名表示bean的id
        @Bean
        //生成一个切面实例
        public RoleAspect getRoleAspect() {
            return new RoleAspect();
        }
    }
    //这个类是对Spring的Bean进行配置,采用的是注解方式
    //表明这是个配置类,相当于xml文件
    @Configuration
    //开启动态代理,开启AOP
    @EnableAspectJAutoProxy
    //扫描这个包下的所有bean
    @ComponentScan("test1")
    public class AopConfig {
        //表示创建一个bean,返回值类型表示bean的类型,方法名表示bean的id
        @Bean
        //生成一个切面实例
        public RoleAspect getRoleAspect() {
            return new RoleAspect();
        }
    }
    结果:
    before....
    {id=1,roleName=role_name_1,note=note_1}
    after....
    afterReturning....
    ############
    before....
    after....
    afterThrowing....
    Exception in thread "main" java.lang.NullPointerException

    显然切面的通知已经通过AOP织入约定的流程中了,这是可以使用AOP来处理一切需要切面的场景了。

    环绕通知

    是spring AOP中最强大的通知,它可以同时实现前置通知和后置通知,还保留了调度被代理对象原有方法的功能,强大而灵活,但如果不需要大量改变业务的逻辑,一般而言并不需要使用它。

    @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....");
        }

    给通知传递参数

    上面的通知除了around()方法之外都是无参的,其实是可以传递参数来使用的。比如:

    @Before("execution(* test1.RoleServiceImpl.printRole(..))"+"&&args(role)")
        public void before(Role role) {
            System.out.println("before....");
        }

    引入

    Spring AOP只是通过动态代理技术,把各类通知织入到它所约定的流程中,而事实上有时我们希望通过引入其他类的方法来得到更好的实现,这时就可以引入其他的方法了。

    比如说引入一个方法检测printRole角色为空时不再打印:

    public interface RoleVerifier {
        public boolean verify(Role role);
    }
    public class RoleVerifierImpl implements RoleVerifier {
        @Override
        public boolean verify(Role role) {
            return role!=null;
        }
    }
    加入RoleVerifier到切面中:
    //value="test1.RoleServiceImpl+":表示对RoleServiceImpl类进行增强,也就是在RoleServiceImpl中引入一个新的接口
        //defaultImpl=RoleVerifierImpl.class:代表其默认的实现类
        @DeclareParents(value="test1.RoleServiceImpl+",defaultImpl=RoleVerifierImpl.class)
        public RoleVerifier roleVerifier;
    ApplicationContext ctx=new AnnotationConfigApplicationContext(AopConfig.class);
            RoleService roleService=(RoleService)ctx.getBean(RoleService.class);
            RoleVerifier roleVerifier=(RoleVerifier)roleService;
            Role role=new Role();
            role.setId(1);
            role.setRoleName("role_name_1");
            role.setNote("note_1");
            if(roleVerifier.verify(role)) {
            roleService.printRole(role);
            }
            System.out.println("############");
            //测试异常通知
            role=null;
            if(roleVerifier.verify(role)) {
                roleService.printRole(role);
                }else {
                    System.out.println("空的");
                }
    只要Spring AOP让代理对象(RoleServiceImpl)挂到RoleService和RoleVerifier两个接口之下,那么就可以把对应的bean通过强制转换,让其在RoleService和RoleVerifier之间相互转换,调用各自的方法。
  • 相关阅读:
    编译安装libusb操作流水账
    SM总线控制器没有驱动 关机后又自动重启
    mtd-utils编译安装过程
    STM32开发/烧录/调试环境搭建 基于:Win10+STM32Cube+openocd+cmsis-dap(dap-link)
    EchoServer和EchoClient模型的改进1之多线程
    CountDownLatch分析
    linux-java环境安装以及ssh
    ServerSocket01
    使用SecureCRT工具部署项目
    javaScript笔记01
  • 原文地址:https://www.cnblogs.com/xc-xinxue/p/12377289.html
Copyright © 2011-2022 走看看