Spring框架入门——AOP
1 第一个Spring AOP程序
接着上一篇博客https://blog.****.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");
}
}
运行结果
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中已经提到了有关切面,切面逻辑的定义。面向切面编程可以通俗地解释为
从前写程序时,我们的程序像一条一条线
面向切面可以理解为
截取了一个一个的切面,直接在上面加入了逻辑,而方法本身并不知道。这样做有很多好处。由于使用动态代理实现,这样做可以降低耦合,实现了代码的重用。
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");
}
}
运行结果
3.2代码解释
这里使用注解的方法实现了相同的功能。可以对比1.1部分观察。