Spring框架入门——AOP

1 第一个Spring AOP程序

    接着上一篇博客https://blog.csdn.net/xiaoy990/article/details/83419186来写,仍然是模拟一个entity+dao+service。这次实现一个为service添加日志的功能,使用AOP思想实现。先看代码。

  1.1 代码

xml文件,增加了aop相关的配置。(还可以使用注解实现,文章第3部分提及)

<?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">

    <context:component-scan base-package="com.xiaoy990"></context:component-scan>

    <aop:config>
        <aop:pointcut id="servicePointcut" expression="execution(public * com.xiaoy990.service..*.add(..))"/>

        <aop:aspect id="logAspect" ref="logInterceptor">
            <aop:before method="before" pointcut-ref="servicePointcut"></aop:before>
        </aop:aspect>
    </aop:config>

</beans>

service

package com.xiaoy990.service;

import com.xiaoy990.entity.User;
import com.xiaoy990.dao.UserDao;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
public class UserService {
    private UserDao userDao;

    @Resource
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void add(User u){
        userDao.save(u);
    }
}

Aspect切面逻辑(需要在切面上增加的逻辑,这里模拟为service增加一个启动日志)

package com.xiaoy990.aop;

import org.springframework.stereotype.Component;

@Component
public class LogInterceptor {

    public void before(){
        System.out.println("service start");
    }
}

 运行结果

Spring框架入门——AOP

1.2 代码解释

    aop:config标签代表了aop的配置信息,pointcut可以理解为是一个切面,Aspect可以理解为是一个切面逻辑。将切面逻辑编织入切面中。这里的动态代理是Aspectj框架实现的,Spring使用了Aspectj框架,所以需要引入aspectjweaver.jar和aspectj.jar,否侧会报classnotfound。

容器在启动时加载了LogInterceptor发现它是一个切面逻辑,可以把它编织入其他方法当中去,它发现使用before指明了它将被编织到servicePointcut这个切面所定义的方法之前,在servicePointcut中使用expression定义的方法是com.xiaoy990.service包以及所有子包中的任何类的任何返回值的add方法。这样就将LogInterceptor这个切面逻辑编织到了servicePointcut这个pointcut中。

2 初识AOP(Aspect Oriented Programming 面向切面编程)

  在1.2中已经提到了有关切面,切面逻辑的定义。面向切面编程可以通俗地解释为

  从前写程序时,我们的程序像一条一条线

Spring框架入门——AOP

  面向切面可以理解为

Spring框架入门——AOP

  截取了一个一个的切面,直接在上面加入了逻辑,而方法本身并不知道。这样做有很多好处。由于使用动态代理实现,这样做可以降低耦合,实现了代码的重用。

3 注解实现

  3.1代码

    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">

    <context:component-scan base-package="com.xiaoy990"></context:component-scan>
    <aop:aspectj-autoproxy/>

    <!--<aop:config>-->
        <!--<aop:pointcut id="servicePointcut" expression="execution(public * com.xiaoy990.service..*.add(..))"/>-->

        <!--<aop:aspect id="logAspect" ref="logInterceptor">-->
            <!--<aop:before method="before" pointcut-ref="servicePointcut"></aop:before>-->
        <!--</aop:aspect>-->
    <!--</aop:config>-->

</beans>

Aspect(LogInterceptor)添加了标签

package com.xiaoy990.aop;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogInterceptor {
    @Before("execution(public * com.xiaoy990.service..*.add(..))")
    public void before(){
        System.out.println("service start");
    }
}

  运行结果

Spring框架入门——AOP

3.2代码解释

    这里使用注解的方法实现了相同的功能。可以对比1.1部分观察。