Spring AOP
3.1 Spring AOP简介
3.1.1 AOP
Aspect-Oriented Programming,面向切面编程。是传统的OOP编程的一个重要的补充。OOP编程,只能子类继承父类的纵向重用。
AOP采用的是横向抽取机制。将分散重复的代码抽离出来,在程序编译或者运行的过程,将代码用到需要的执行地方。
3.1.2 AOP术语
Aspect(切面)
JoinPoint(连接点)
Pointcut(切入点)
Advice(通知增强处理)
Target Object(目标对象)
Proxy(代理)
Weaving(织入)
3.2 AspectJ开发
基于XML配置
1.UserDao.java
package com.sty.dao;
public interface UserDao {
//添加用户
void add();
//删除用户
void delete();
}
2.UserDaoImpl.java
package com.sty.dao;
public class UserDaoImpl implements UserDao {
public void add() {
System.out.println("增加一个用户");
}
public void delete() {
System.out.println("删除一个用户");
}
}
3.MyAspect.java
package com.sty.dao.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.lang.NonNull;
/*
* 面向切面类
* */
public class MyAspect {
/*1.前置通知*/
public void myBefore(@NonNull JoinPoint joinPoint){
System.out.println("前置通知:模拟执行权限。。。。。");
System.out.println("目标类是:"+joinPoint.getTarget());
System.out.println(","+"被植入增强处理的目标方法是"+joinPoint.getSignature().getName());
}
/*2.后置通知*/
public void myAfterReturning(@NonNull JoinPoint joinPoint){
System.out.println("后置通知:模拟记录日志");
System.out.println("被植入增强处理的目标方法是"+joinPoint.getSignature().getName());
}
/*3.环绕通知
* ProceedingJoinPoint 是JoinPoint子接口,表示可执行的目标方法
* 1. 必须是Object返回值
* 2. 参数必须是ProceedingJoinPoint类型
* 3.必须throws Throwable
*
*
* */
public Object myAround(@NonNull ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕开始:执行目标方法之前,模拟开启事务‘。。。。");
//执行当前的方法
Object proceed = proceedingJoinPoint.proceed();
System.out.println("环绕结束:执行目标方法之后,模拟关闭事务‘。。。。");
return proceed;
}
/*4.异常通知*/
public void myAfterThrowing( JoinPoint joinPoint, @NonNull Throwable throwable){
System.out.println("异常通知:出错了"+ throwable.getMessage());
}
/*5.最终通知*/
public void myAfter(){
System.out.println("模拟方法,释放资源");
}
}
4.ApplicationContext.xml
<?xml version="1.0" encoding="UTF8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xmlns="http://www.springframework.org/schema/beans"
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">
<!--1.目标类-->
<bean id="userDao" class="com.sty.dao.UserDaoImpl"/>
<!--2.切面-->
<bean id="myAspect" class="com.sty.dao.aspect.MyAspect"/>
<!--3.Aop编程-->
<aop:config>
<!--3.1配置切面-->
<aop:aspect id="aspect" ref="myAspect">
<!--3.2配置切点-->
<aop:pointcut id="myPointCut" expression="execution(* com.sty.dao.UserDaoImpl.add(..))"/>
<!--3.3配置通知-->
<aop:before method="myBefore" pointcut-ref="myPointCut"/>
<aop:around method="myAround" pointcut-ref="myPointCut"/>
<aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="returnVal"/>
<aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="throwable"/>
<aop:after method="myAfter" pointcut-ref="myPointCut"/>
</aop:aspect>
</aop:config>
</beans>
5.测试
public class MyTest2 {
/*自定义切面*/
@Test
public void TestDiy() {
ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
UserDao userDao = (UserDao) context.getBean("userDao");
userDao.add();
System.out.println("------------------");
userDao.delete();
注解配置
1.UserDao
package com.sty.AnnotationDao;
import org.springframework.stereotype.Repository;
public interface UserDao {
//添加用户
void add();
//删除用户
void delete();
}
2.UserDaoImpl.java
package com.sty.AnnotationDao;
import org.springframework.stereotype.Repository;
@Repository("userDao")
public class UserDaoImpl implements UserDao {
public void add() {
System.out.println("增加一个用户");
}
public void delete() {
System.out.println("删除一个用户");
}
}
3.myAspect.java
package com.sty.AnnotationDao.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
/*
* 面向切面类
* */
@Component
@Aspect //定义一个切面
public class MyAspect {
/*定义一个表达式*/
@Pointcut("execution(* com.sty.AnnotationDao.*.*(..))")
public void myPointCut(){}
/*1.前置通知*/
@Before("myPointCut()")
public void myBefore(@NonNull JoinPoint joinPoint){
System.out.println("前置通知:模拟执行权限。。。。。");
System.out.println("目标类是:"+joinPoint.getTarget());
System.out.println(","+"被植入增强处理的目标方法是"+joinPoint.getSignature().getName());
}
/*2.后置通知*/
@After("myPointCut()")
public void myAfterReturning(@NonNull JoinPoint joinPoint){
System.out.println("后置通知:模拟记录日志");
System.out.println("被植入增强处理的目标方法是"+joinPoint.getSignature().getName());
}
/*3.环绕通知
* ProceedingJoinPoint 是JoinPoint子接口,表示可执行的目标方法
* 1. 必须是Object返回值
* 2. 参数必须是ProceedingJoinPoint类型
* 3.必须throws Throwable
*
*
* */
@Around("myPointCut()")
public Object myAround(@NonNull ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕开始:执行目标方法之前,模拟开启事务‘。。。。");
//执行当前的方法
Object proceed = proceedingJoinPoint.proceed();
System.out.println("环绕结束:执行目标方法之后,模拟关闭事务‘。。。。");
return proceed;
}
/*4.异常通知*/
@AfterThrowing(value = "myPointCut()",throwing = "throwable")
public void myAfterThrowing( JoinPoint joinPoint, @NonNull Throwable throwable){
System.out.println("异常通知:出错了"+ throwable.getMessage());
}
/*5.最终通知*/
@After("myPointCut()")
public void myAfter(){
System.out.println("模拟方法,释放资源");
}
}
4.application.xml
<?xml version="1.0" encoding="UTF8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xmlns="http://www.springframework.org/schema/beans"
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.sty"/>
<!--启动基于注解的声名式Aspect支持-->
<aop:aspectj-autoproxy/>
</beans>