美文网首页
Spring AOP 基本用法

Spring AOP 基本用法

作者: shpunishment | 来源:发表于2018-08-23 14:49 被阅读0次

    导入
    aopalliance-1.0.jar
    aspectjrt-1.7.4.jar
    aspectjweaver-1.7.4.jar

    Spring AOP 的使用可以注解或是xml配置文件的形式,使用AOP尽量使用注解的形式

    AOP注解的方式

    定义切面和连接点 LogAspect

    package com.shpun.aop;
    import org.aspectj.lang.annotation.*;
    
    @Aspect
    public class LogAspect {
    
        /*
        或使用@Pointcut,不用每个都写那么长的类名
    
        @Pointcut("execution(* com.shpun.service..*(..))")
        public void print(){}
        @Before("print()")
        @After("print()")
        @AfterReturning("print()")
        @AfterThrowing("print()")
        */
    
        // 切入点为 com.shpun.service包下的所有类的所有方法 
        // 在被代理对象的方法 前 先调用 
        @Before("execution(* com.shpun.service..*(..))")
        public void before(){
            System.out.println("LogAspect before ... ");
        }
        // 在被代理对象的方法 后 调用  
        @After("execution(* com.shpun.service..*(..))")
        public void after(){
            System.out.println("LogAspect after ... ");
        }
        // 在被代理对象的方法 正常返回 后调用  
        @AfterReturning("execution(* com.shpun.service..*(..))")
        public void afterReturning(){
            System.out.println("LogAspect afterReturning ... ");
        }
        // 在被代理对象的方法 抛出异常 后调用  
        @AfterThrowing("execution(* com.shpun.service..*(..))")
        public void afterThrowing(){
            System.out.println("LogAspect afterThrowing ... ");
        }
    }
    

    接口和实现类

    package com.shpun.service;
    public interface ShowService {
        void showCustomer(Customer customer);
    }
    
    package com.shpun.service;
    
    @Service
    public class ShowServiceImpl implements ShowService {
        @Override
        public void showCustomer(Customer customer) {
            System.out.println("ShowServiceImpl : id: "+customer.getId()+" name: "+customer.getName()+" note: "+customer.getNote());
        }
    }
    

    JavaBean

    package com.shpun.entity;
    public class Customer {
        private String id;
        private String name;
        private String note;
        /*getter setter*/
    }
    

    纯注解的方式使用,需要写一个配置类进行配置

    package com.shpun.aop;
    
    @Configuration
    @EnableAspectJAutoProxy
    @ComponentScan("com.shpun.service")
    public class AOPConfig {
    
        @Bean
        public LogAspect getLogAspect(){
            return new LogAspect();
        }
    }
    

    或者是使用xml配置文件配置

    <?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.xsd
           http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop.xsd
        ">
        <!-- 扫描com.shpun下注解 -->
        <context:component-scan base-package="com.shpun"/>
        <!-- 自动代理 -->
        <aop:aspectj-autoproxy/>
    </beans>
    

    测试

    public class TestAOP {
        public static void main(String[] main){
            ApplicationContext context = new AnnotationConfigApplicationContext(AOPConfig.class);
            //ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
            ShowService showServiceImpl = context.getBean(ShowService.class);
    
            Customer customer = new Customer();
            customer.setId("1");
            customer.setName("AOP");
            customer.setNote("AOP Test");
            showServiceImpl.showCustomer(customer);
    
            System.out.println("测试异常情况");
            customer = null;
            showServiceImpl.showCustomer(customer);
        }
    }
    

    输出结果

    ShowServiceImpl : id: 1 name: AOP note: AOP Test
    LogAspect after ... 
    LogAspect afterReturning ... 
    测试异常情况
    LogAspect before ... 
    LogAspect after ... 
    LogAspect afterThrowing ... 
    

    再使用Around,在LogAspect添加

        @Around("execution(* com.shpun.service..*(..))")
        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 ...
    LogAspect before ... 
    ShowServiceImpl : id: 1 name: AOP note: AOP Test
    around after ...
    LogAspect after ... 
    LogAspect afterReturning ... 
    测试异常情况
    around before ...
    LogAspect before ... 
    around after ...
    LogAspect after ... java.lang.NullPointerException
                                    
    LogAspect afterReturning ... 
    

    ps:

    当我有多个ShowService的实现类时,比如多一个实现类ShowServiceTwoImpl,并加上@Service

    1.如果实现类ShowServiceTwoImpl,class没加上@Service,继续使用如下方式获取bean,则获取的是ShowServiceImpl;加上@Service,则会得到异常,原因是有两个实现类,Spring不知获取哪一个

    ShowService showServiceImpl = context.getBean(ShowService.class);
    
    NoUniqueBeanDefinitionException: No qualifying bean of type 'com.shpun.service.ShowService' 
    available: expected single matching bean but found 2: showServiceImpl,showServiceTwoImpl
    

    2.搜索结果显示该错误多是@Autowired是出现,有的说是Spring没有扫描到,但我换成xml形式扫描,错误一样。未知

    ShowService showServiceImpl = context.getBean(ShowServiceImpl.class);
    
    NoSuchBeanDefinitionException: No qualifying bean of type 'com.shpun.service.ShowServiceImpl' available
    

    3.因为@Service默认使用类名首字母小写的形式生成bean,尝试类名查找

    ShowService showServiceImpl = context.getBean("showServiceImpl",ShowServiceImpl.class);
    
    BeanNotOfRequiredTypeException: Bean named 'showServiceImpl' is expected to be of type 'com.shpun.service.ShowServiceImpl' 
    but was actually of type 'com.sun.proxy.$Proxy21'
    

    BeanNotOfRequiredTypeException 切面异常

    目前使用的是配置类的形式,所以在AOPConfig里面

    @EnableAspectJAutoProxy(proxyTargetClass = true)
    

    若使用xml配置文件的形式,改为

    <aop:aspectj-autoproxy proxy-target-class="true"/>
    

    测试AOP成功

    ShowService showServiceImpl = context.getBean("showServiceImpl",ShowServiceImpl.class);
    ShowService showServiceTwoImpl = context.getBean("showServiceTwoImpl",ShowServiceTwoImpl.class);
    

    输出结果

    LogAspect before ... 
    ShowServiceImpl : id: 1 name: AOP note: AOP Test
    LogAspect after ... 
    LogAspect afterReturning ... 
    LogAspect before ... 
    two com.shpun.entity.Customer@7c83dc97
    LogAspect after ... 
    LogAspect afterReturning ...
    测试异常情况
    LogAspect before ... 
    LogAspect after ... 
    LogAspect afterThrowing ... 
    

    一个接口的多个实现类,通过getBean使用时,需要proxy-target-class="true"。

    <aop:aspectj-autoproxy/> 默认jdk代理
    <aop:aspectj-autoproxy proxy-target-class="true"/> 设置为true,为cglib代理
    

    相关文章

      网友评论

          本文标题:Spring AOP 基本用法

          本文链接:https://www.haomeiwen.com/subject/fjjuiftx.html