1. AspectJ的简介
- AspectJ是一个基于java语言的AOP框架
- spring 2.0以后新增了对AspectJ切点表达式的支持
- @AspectJ,允许直接在Bean类中定义切面
- 新版本的spring框架,建议使用AspectJ方式来开发AOP
2. 环境准备
<?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" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
3. AspectJ 通知类型列举
- @Before 前置通知
- @AfterReturning 后置通知
- @Around 环绕通知,最强大的,可以阻止方法执行
- @AfterThrowing 异常抛出通知
- @After 最终通知,无论是否有异常
4. excution函数语法
- 通过excution函数,可以定义切点的方法切入
- 语法:
- execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)
- 例如:
- 匹配所有类public方法 execution(public * * ())
- 匹配指定包下所有类方法 execution(* com.aop.dao.*(..)) 不包含子包中的类
- execution(* com.aop.dao..*(..)) 包、子孙包下的所有类
- 匹配指定类所有方法 execution(* com.aop.dao.UserDao.*(..))
- 匹配实现特定接口所有类的方法 execution(* com.aop.dao.IDao+.*(..))
- 匹配所有save开头的方法 execution(* save*(..))
5. 栗子
package com.aop.aspectj;
public class ProductDao {
public void save(){
System.out.println("save");
}
public void update(){
System.out.println("update");
}
public void delete(){
System.out.println("delete");
}
public void findone(){
System.out.println("findone");
}
public void findall(){
System.out.println("findall");
int i = 1 / 0;
}
}
package com.aop.aspectj;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class MyAspect {
@Before(value = "execution(* com.aop.aspectj.ProductDao.save(..))")
public void before(JoinPoint point) {
System.out.println("==========before========" + point);
}
@AfterReturning(value = "execution(* com.aop.aspectj.ProductDao.delete(..))", returning="result")
public void afterReturning(Object result) {
System.out.println("===========after returning========" + result);
}
@After(value = "execution(* com.aop.aspectj.ProductDao.findone(..))")
public void after() {
System.out.println("=========after==============");
}
@Around(value = "execution(* com.aop.aspectj.ProductDao.update(..))")
public Object around(ProceedingJoinPoint point) throws Throwable {
System.out.println("===========around start===========");
Object o = point.proceed();
System.out.println("==========around end========");
return o;
}
@AfterThrowing(value="execution(* com.aop.aspectj.ProductDao.findall(..))", throwing="e")
public void afterThrowable(Throwable e) {
System.out.println("===========throw============" + e);
}
}
<?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" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 开启aspectj自动代理 -->
<aop:aspectj-autoproxy/>
<bean id="productDao" class="com.aop.aspectj.ProductDao"/>
<bean class="com.aop.aspectj.MyAspect"/>
</beans>
package com.aop.aspectj;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application-context-aop-aspectj.xml")
public class SpringDemo {
@Resource(name="productDao")
private ProductDao dao;
@Test
public void demo1() {
dao.save();
dao.delete();
dao.update();
dao.findall();
dao.findone();
}
}
6. 通过@Pointcut 为切点命名
- 在每个通知内定义切点,会造成工作量大,不易维护,对于重复的切点,可以使用@Pointcut进行定义
- 切点方法:private void 无参数方法,方法名为切点名
- 当通知有多个切点,可以使用||进行连接
@Around(value = "pointcut1()||pointcut2()||pointcut3()||pointcut4()||pointcut5()")
public Object around(ProceedingJoinPoint point) throws Throwable {
System.out.println("===========around start===========");
Object o = point.proceed();
System.out.println("==========around end========");
return o;
}
@Pointcut(value = "execution(* com.aop.aspectj.ProductDao.save(..))")
private void pointcut1() {
}
@Pointcut(value = "execution(* com.aop.aspectj.ProductDao.delete(..))")
private void pointcut2() {
}
@Pointcut(value = "execution(* com.aop.aspectj.ProductDao.findone(..))")
private void pointcut3() {
}
@Pointcut(value = "execution(* com.aop.aspectj.ProductDao.update(..))")
private void pointcut4() {
}
@Pointcut(value = "execution(* com.aop.aspectj.ProductDao.findall(..))")
private void pointcut5() {
}