准备工作:
1、Spring框架一般都是基于AspectJ实现AOP操作
(1)AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spirng框架一起使用,进行AOP操作
2、基于AspectJ实现AOP操作
(1)基于xml配置文件实现
(2)基于注解方式实现(使用)
3、在项目工程里面引入AOP相关依赖
spring基本jar包:
spring-aop-5.2.6.RELEASE.jar
spring-beans-5.2.6.RELEASE.jar
spring-context-5.2.6.RELEASE.jar
spring-core-5.2.6.RELEASE.jar
spring-expression-5.2.6.RELEASE.jar
aop部分jar包:
spring-aspects-5.2.6.RELEASE.jar
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
其他:
commons-logging-1.1.1.jar
druid-1.1.9.jar
4、切入点表达式
(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强
(2)语法结构:execution([权限修饰符][返回类型][类全路径][方法名称]([参数列表]))
举例1:对com.atguigu.dao.BookDao类里面的add进行增强
execution(* com.atguigu.dao.BookDao.add(..))
举例2:对com.atguigu.dao.BookDao类里面的所有的方法进行增强
execution(* com.atguigu.dao.BookDao.*(..))
举例3:对com.atguigu.dao包里面所有类,类里面所有方法进行增强
execution(* com.atguigu.dao.*.*(..))
代码演示五种通知
User:
@Component
public class User {
public void add(){
// int i = 1/0;
System.out.println("add 业务逻辑执行.....");
}
}
增强代理类:
//增强的类
@Aspect //生成代理对象
@Component
public class UserProxy {
//前置通知
@Before("execution(* com.spring5.aopanno.User.add(..))")//前置通知
public void before(){
System.out.println("before-前置通知-......");
}
//后置通知(返回通知)-方法执行后-返回结果之后执行
@AfterReturning("execution(* com.spring5.aopanno.User.add(..))")
public void afterReturning(){
System.out.println("afterReturning-后置通知(返回通知)-......");
}
//最终通知-方法执行之后执行
@After("execution(* com.spring5.aopanno.User.add(..))")
public void after(){
System.out.println("after-最终通知......");
}
//异常通知
@AfterThrowing("execution(* com.spring5.aopanno.User.add(..))")
public void afterThrowing(){
System.out.println("afterThrowing-异常通知......");
}
//环绕通知
@Around("execution(* com.spring5.aopanno.User.add(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("around-环绕之前通知-......");
joinPoint.proceed();
System.out.println("around-环绕之后通知-......");
}
}
xml配置:
引入 context和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: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.spring5.aopanno"></context:component-scan>
<!--启用aspectj-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
junit测试类:
@Test
public void testAop(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
User user = context.getBean("user", User.class);
user.add();
}
正常流程结果:
around-环绕之前通知-......
before-前置通知-......
add 业务逻辑执行.....
around-环绕之后通知-......
after-最终通知......
afterReturning-后置通知(返回通知)-......
业务逻辑异常时结果:
around-环绕之前通知-......
before-前置通知-......
after-最终通知......
afterThrowing-异常通知......
相同的切入点抽取
方便相同表达式修改
//相同切入点抽取
@Pointcut("execution(* com.spring5.aopanno.User.add(..))")
public void pointTest(){
}
//前置通知
@Before("pointTest()")//前置通知
public void before(){
System.out.println("before-前置通知-......");
}
多个增强类,作用于同一方法,设置优先级
数字越小,优先级越高
@Aspect
@Component
@Order(1)
public class PersonProxy {
@Before("execution(* com.spring5.aopanno.User.add(..))")
public void before(){
System.out.println("person before .....");
}
}
效果:
person before .....
around-环绕之前通知-......
before-前置通知-......
add 业务逻辑执行.....
around-环绕之后通知-......
after-最终通知......
afterReturning-后置通知(返回通知)-......
完成注解开发,使用配置类
@Configuration
@ComponentScan(basePackages = {"com.spring5.aopanno"})
@EnableAspectJAutoProxy
public class SpringConfig {
}
junit测试:
@Test
public void testAopAnno(){
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
User user = context.getBean("user", User.class);
user.add();
}
XML方式实现通知
public class Book {
public void buy(){
// int i = 1/0;
System.out.println("buy .....");
}
}
public class BookProxy {
public void before(){
System.out.println("before........");
}
public void afterReturning(){
System.out.println("afterReturning........");
}
public void after(){
System.out.println("after........");
}
public void afterThrowing(){
System.out.println("afterThrowing........");
}
public void around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("around-环绕之前通知-......");
joinPoint.proceed();
System.out.println("around-环绕之后通知-......");
}
}
<?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">
<bean id="book" class="com.spring5.aopxml.Book"></bean>
<bean id="bookProxy" class="com.spring5.aopxml.BookProxy"></bean>
<!--配置aop增强-->
<aop:config>
<!--切入点-->
<aop:pointcut id="p" expression="execution(* com.spring5.aopxml.Book.buy(..))"/>
<!--配置切面-->
<aop:aspect ref="bookProxy">
<!--增强作用在具体的方法上-->
<aop:before method="before" pointcut-ref="p"></aop:before>
<aop:after-returning method="afterReturning" pointcut-ref="p"></aop:after-returning>
<aop:after method="after" pointcut-ref="p"></aop:after>
<aop:after-throwing method="afterThrowing" pointcut-ref="p"></aop:after-throwing>
<aop:around method="around" pointcut-ref="p"></aop:around>
</aop:aspect>
</aop:config>
</beans>