首页 > 技术文章 > Spring_AOP

zhouchangyang 2019-05-25 16:30 原文

Spring  AOP

首先需要了解springAOP的一些重要概:

1.切点:定义的就是为哪些方法增加功能  
2.通知:定义的就是何时何事
3.切面: 切面是一个类,包含了切点和通知的类
4.织入:把切面整合到目标类的过程
5.接入点:里面保存着当前执行的方法的信息

springAOP利用了AspectJ个框架的配置方式.,就是里面的注解所以需要先导入一个jar包.

 

具体实现:

1.创建一个类,并spring注解标记.里面写原来执行的功能.

@Service
public class BookSericeImpl implements BookSerice {
    @Override
    public void addOne(BokBean bokBean) {
        System.out.println("执行逻辑:插入一本书");
    }

    @Override
    public void deletOne(Long bookId) {
        System.out.println("执行逻辑:删除一本书");

        //睡眠1秒
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 

2.创建一个切面,即一个类,用@Aspect注解把这个类标记为切面,

切点:  在切面里面为指定的类的方法添加切点.

通知:  在围绕切点选择想要在什么时候增强什么功能.

@Aspect
@Component
public class LogAspect {

    //1.切点
    //切点实际上就是一个表达式,规定为哪些方法做增强的表达式
    //表示Service类中的所有方法
    @Pointcut("execution(* com.lanou.demo.service.impl.*.*(..))")
    public void allServiceMethod(){

    }

    //2.通知
    //前置通知
    @Before("allServiceMethod()")     //该注解默认等于  @Before(value = "allServiceMethod()")
    public void before(JoinPoint jp){

        //JoinPoint接入点:
        //  可以根据需要获取下面的相关信息

        //获取被代理对象
        Object target = jp.getTarget();
        //获取方法签名
        Signature signature = jp.getSignature();
        //获取方法的参数
        Object[] args = jp.getArgs();
        System.out.println("方法之前执行");
    }
    //后置通知
    @After("allServiceMethod()")
    public void after(JoinPoint jp){

        System.out.println("方法执行后");
    }

    //方法正常执行的通知
    //returning参数:接受参数
    @AfterReturning(value = "allServiceMethod()",returning = "value")
    public void returnLog(JoinPoint jp,Object value){

        System.out.println("方法正常执行"+value);
    }

    //异常通知
    @AfterThrowing(value = "allServiceMethod()",throwing = "ex")
    public void throwLog(JoinPoint jp,Exception ex){
        System.out.println("方法异常了");
    }

    //环绕通知 :相当于在原来方法周围添加功能.
    //ProceedingJoinPoint 是JoinPoint 的子类
    @Around("allServiceMethod()")
    public Object around(ProceedingJoinPoint jp){
        try {
            long start = System.currentTimeMillis();   //写在原来方法的前面相当于前置通知
            Object proceed = jp.proceed();   //这是执行的原来的方法
            long time = System.currentTimeMillis()-start;   //写在原来方法后面相当于后置通知
            System.out.println("运行时长"+time);
          return proceed;

        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return null;
    }
}

 

3.创建好切面后,需要在spring配置文件中配置aop,让spring根据注解自动加载切面

<?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:mvc="http://www.springframework.org/schema/mvc" 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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">


    <context:component-scan base-package="com.lanou.demo"/>
    <mvc:annotation-driven/>
    <aop:config>
        
        <aop:pointcut id="service" expression="execution(* com.lanou.demo.service.impl.*.*(..)))"/>
        <aop:aspect ref="logAspect" order="1">
            <aop:before method="before" pointcut-ref="service"/>
            
        </aop:aspect>
        
    </aop:config>


    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!--配置可以根据注解自动加切面的功能-->
    <!--第一种的配置方式:常用-->
<aop:aspectj-autoproxy/>
<!--第二种配置方式: 这种配置方式不需要再用注解标记,而是在这里面指定要加载的类和方法 里面的参数跟注解方式注解的参数对应. --> <!--<aop:config>--> <!--<aop:pointcut id="service" expression="execution(* com.lanou.demo.service.impl.*.*(..)))"/>--> <!--<aop:aspect ref="logAspect" order="1">--> <!--<aop:before method="before" pointcut-ref="service"/>--> <!--</aop:aspect>--> <!--</aop:config>--> </beans>

 

4.调用bookserviceImpl中的方法,(这里用spring测试类测试)

//spring测试类注解.
@RunWith(SpringJUnit4ClassRunner.class)
//加载spring的配置文件
@ContextConfiguration("classpath:application-context.xml")
public class BookSericeImplTest {

    @Resource
    private BookSerice bookSerice;

    @Test
    public void text1() {
        
//调用原来方法
this.bookSerice.deletOne(33L); } }

执行结果如下:

会发现为类或方法配置好切点后,当执行该方法时,spring会自动为该方法添加增强的功能.

INFO: HV000001: Hibernate Validator 6.0.16.Final
方法之前执行
执行逻辑:删除一本书
运行时长1002
方法执行后
方法正常执行null

Process finished with exit code 0

 

推荐阅读