1、实现spring AOP所需要的jar
AOP所需要的jar:
- aspectjrt.jar
- aspectjweaver.jar
- cglib.jar
同时需要spring框架相关jar:
- spring-context.jar
- spring-context-support.jar
- spring-tx.jar
单元测试jar
- junit.jar
项目基于maven进行管理,完整的pom.xml配置文件如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test.spring</groupId>
<artifactId>support</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>support</name>
<url>http://maven.apache.org</url>
<properties>
<spring.version>4.2.6.RELEASE</spring.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- AOP begin -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.7.4</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.4</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.1</version>
</dependency>
<!-- AOP end -->
<!-- TEST begin -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- TEST end -->
</dependencies>
</project>
2、基于配置的spring-context.xml文件规范、AOP配置
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<!-- 注册登录业务bean -->
<bean name="loginService" class="com.test.spring.aop.LoginServiceImpl"></bean>
<!-- 注册登录业务日志切面bean -->
<bean name="loginLogAspect" class="com.test.spring.aop.LoginLogAspect"></bean>
<!-- 配置spring AOP,设置aop:config的proxy-target-class="true"则强制使用CGLIB代理 -->
<aop:config>
<!-- 配置切面 -->
<aop:aspect id="llAspect" ref="loginLogAspect">
<!-- 配置切入点表达式,即连接点断言 -->
<aop:pointcut id="loginPointcut" expression="execution(* com.test.spring.aop.*.*(..))"/>
<!-- 配置通知,pointcut-ref属性指向上面的切入点,可以直接使用pointcut属性,配置执行表达式 -->
<aop:before method="beforeLogin" pointcut-ref="loginPointcut"/>
<aop:after method="afterLogin" pointcut-ref="loginPointcut"/>
<aop:around method="aroundLogin" pointcut-ref="loginPointcut"/>
<aop:after-returning method="afterReturningLogin" pointcut="execution(* com.test.spring.aop.*.*(..))"/>
<aop:after-throwing method="afterThrowingLogin" pointcut="execution(* com.test.spring.aop.*.*(..))"/>
</aop:aspect>
</aop:config>
</beans>
<beans>
是Spring的配置标签,beans里面几个重要的属性:
xmlns:是默认的xml文档解析格式,即spring的beans。地址是http://www.springframework.org/schema/beans。
通过设置这个属性,所有在beans里面声明的属性,可以直接通过<>来使用,比如<bean>
等等。xmlns:xsi:是xml需要遵守的规范,通过URL可以看到,是w3的统一规范,后面通过xsi:schemaLocation来定位所有的解析文件。
xmlns:aop:这个是重点,是我们这里需要使用到的一些语义规范,与面向切面AOP相关。
xmlns:tx:Spring中与事务相关的配置内容。
Spring所有的切面和通知器都必须放在一个<aop:config>
内(可以配置包含多个<aop:config>
元素),每一个<aop:config>
可以包含pointcut,advisor和aspect元素(如何全部存在,它们必须按照这个顺序进行相应的声明和配置)
pointcut切面表达式配置简单介绍:
- execution(public**(..)) 切入点为执行所有public方法时
- execution(set(..))切入点为执行所有set方法开始的方法时
- execution(com.xyz.service.AccountService.(..))切入点为执行AccountService类中的所有方法时
- execution(*com.xyz.service..(..)) 切入点为执行com.xyz.service包下的所有方法时
- execution(*com.xyz.service…(..)) 切入点为执行com.xyz.service包及其子包下的所有方法时
以下只有Spring中才能用,还有很多配置,可以查阅spring的官方文档
- within(com.xyz.service.*)
- within(com.xyz.service..*)within用于匹配制定类型内的方法执行
- this(com.xyz.service.AccountService) this用于匹配当前AOP代理对象类型的执行方法
- taget用于匹配当前目标对象类型的执行方法
3、业务接口、业务实现类和切面类、通知
业务接口:
package com.test.spring.aop;
/**
* @Description: 业务接口
*/
public interface LoginService {
public void login() throws Exception;
}
业务实现类:
package com.test.spring.aop;
/**
* @Description: 业务实现类
*/
public class LoginServiceImpl implements LoginService {
@Override
public void login() throws Exception {
System.out.println("LoginServiceImpl login 登录成功。。。");
//业务方法出现异常,则触发抛出异常后通知
//throw new Exception("");
}
}
登录业务日志的切面:
package com.test.spring.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* @Description: 登录业务日志的切面
*/
public class LoginLogAspect {
//前置通知,除了环绕通知,其它所有通知第一个参数可以是JoinPoint类型
public void beforeLogin(JoinPoint point){
System.out.println("前置通知。。。");
}
//后置通知
public void afterLogin(){
System.out.println("后置通知。。。");
}
//环绕通知,有返回值,第一个参数必须是ProceedingJoinPoint类型
public Object aroundLogin(ProceedingJoinPoint point) throws Throwable{
System.out.println("环绕通知,业务方法执行之前。。。");
Object obj = point.proceed();//向下执行业务方法
System.out.println("环绕通知,业务方法执行之后。。。");
return obj;
}
//返回后通知
public void afterReturningLogin(){
System.out.println("返回后通知。。。");
}
//抛出异常后通知
public void afterThrowingLogin(){
System.out.println("抛出异常后通知。。。");
}
}
单元测试类:
/**
* @Description: 单元测试类
*/
public class TestSpringAop {
@Test
public void testSpringAop(){
LoginService loginService = this.getBean("loginService");
try {
//触发业务方法,即触发连接点
loginService.login();
} catch (Exception e) {
e.printStackTrace();
}
}
//以下为容器实例声明及初始化、销毁
private ClassPathXmlApplicationContext context;
@Before
public void before(){
try {
context = new ClassPathXmlApplicationContext("spring-context.xml");
context.start();
} catch (BeansException e) {
e.printStackTrace();
}
}
@After
public void after(){
context.destroy();
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
@SuppressWarnings("unchecked")
public <T> T getBean(String name) {
return (T) context.getBean(name);
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
public <T> T getBean(Class<T> requiredType) {
return context.getBean(requiredType);
}
}
执行结果如下:
前置通知。。。
环绕通知,业务方法执行之前。。。
LoginServiceImpl login 登录成功。。。
返回后通知。。。
环绕通知,业务方法执行之后。。。
后置通知。。。
如果同时配置所有类型通知,它们的执行顺序是:前置通知、环绕通知业务方法执行之前、业务方法、(返回后通知、环绕通知业务方法执行之后)/抛出异常后通知、后通知、