美文网首页
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