AOP的实现
2024-09-07 13:31:06
AOP基于xml配置方式实现
Spring基于xml开发AOP
- 定义目标类(接口及实现类)
/**
* 目标类
*/
public interface UserService {
//业务方法
public void getById();
public void add();
public void delete();
public String update();
public void batch();
}
public class UserServiceImpl implements UserService {
@Override
public void getById() {
System.out.println("UserServiceImpl类的getById方法被调用...");
//抛出异常
System.out.println(1/0);
}
@Override
public void add() {
System.out.println("UserServiceImpl类的add方法被调用...");
}
@Override
public void delete() {
System.out.println("UserServiceImpl类的delete方法被调用...");
// System.out.println(1/0);
}
@Override
public String update() {
System.out.println("UserServiceImpl类的update方法被调用...");
// System.out.println(1/0);
return "update的返回值";
}
@Override
public void batch() {
System.out.println("UserServiceImpl类的batch方法被调用...");
}
}
- 定义切面类
/**
* 切面
*/
public class UserAspect {
//前置通知
public void beforeAdvice(JoinPoint jp){
//获取切入点的方法的名称
String name = jp.getSignature().getName();
System.out.println("前置通知切入点的方法的名称:"+name);
System.out.println("前置通知");
} //后置通知
public void afterAdvice(JoinPoint jp){
//获取切入点的方法的名称
String name = jp.getSignature().getName();
System.out.println("后置通知切入点的方法的名称:"+name);
System.out.println("后置通知");
} //返回通知
//可以获取object类型的返回值
//注意:result名称必须和配置文件中的returning的名称保持一致
public void afterReturningAdvice(JoinPoint jp,Object result){
//获取切入点的方法的名称
String name = jp.getSignature().getName();
System.out.println("返回通知切入点的方法的名称:"+name);
//打印返回值
System.out.println(result);
System.out.println("返回通知");
} //异常通知
public void exceptionAdvice(JoinPoint jp,Exception ex){
//获取切入点的方法的名称
String name = jp.getSignature().getName();
System.out.println("异常通知切入点的方法的名称:"+name);
//打印异常信息
System.out.println(ex.getMessage());
System.out.println("异常通知");
} //环绕通知
//必须有一个参数:ProceedingJoinPoint
//有返回值:Object
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("环绕通知前");
//执行业务逻辑方法
Object result = pjp.proceed();
//获取切入点的方法的名称
String name = pjp.getSignature().getName();
System.out.println("环绕通知切入点的方法的名称:"+name);
System.out.println("环绕通知后");
return result;
}
}
- 配置spring核心配置文件
<?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-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
<!-- 把切面和业务对象放到容器中 -->
<bean id="userAspect" class="spring.aop.xml.UserAspect"></bean>
<bean id="userServiceImpl" class="spring.aop.xml.UserServiceImpl"></bean> <!-- 配置aop的实现 -->
<aop:config>
<!--
切入点的配置
expression(切入点表达式):指定切哪个方法
-->
<aop:pointcut expression="execution(* *.add*(..))" id="pointCut01"/>
<aop:pointcut expression="execution(* *.delete*(..))" id="pointCut02"/>
<aop:pointcut expression="execution(* *.update*(..))" id="pointCut03"/>
<aop:pointcut expression="execution(* *.getById*(..))" id="pointCut04"/>
<aop:pointcut expression="execution(* *.batch*(..))" id="pointCut05"/> <!-- 切面的配置 -->
<aop:aspect ref="userAspect">
<!--
前置通知的配置:在pointCut01切入点的位置添加beforeAdvice的通知
-->
<aop:before method="beforeAdvice" pointcut-ref="pointCut01"/> <!--
后置通知的配置:在pointCut02切入点的位置添加afterAdvice的通知
-->
<aop:after method="afterAdvice" pointcut-ref="pointCut02"/> <!--
返回通知的配置:在pointCut03切入点的位置添加afterReturningAdvice的通知
returning:返回值的参数名称
-->
<aop:after-returning method="afterReturningAdvice" pointcut-ref="pointCut03" returning="result"/> <!--
异常通知的配置:在pointCut04切入点的位置添加exceptionAdvice的通知
throwing:抛出异常的名称,必须和通知上的形参名称一致
-->
<aop:after-throwing method="exceptionAdvice" pointcut-ref="pointCut04" throwing="ex"/> <!--
环绕通知的配置:在pointCut05切入点的位置添加aroundAdvice的通知
-->
<aop:around method="aroundAdvice" pointcut-ref="pointCut05"/>
</aop:aspect>
</aop:config>
</beans>
- 测试
//使用xml方式配置AOP
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-aop-xml.xml")
public class XmlAopTest {
//注入业务对象
@Autowired
private UserService userService; //测试AOP,对切入点进行增强
@Test
public void test(){
//前置通知的测试
// userService.add(); //后置通知的测试(无论有没有异常都会执行)
// userService.delete(); //返回通知的测试(只有业务方法正常执行时,才会执行的通知)
// userService.update(); //异常通知的测试
// userService.getById(); //环绕通知的测试
userService.batch();
}
}
AOP的切入点表达式execution
表达式的写法:修饰关键词 返回值类型 包名.类名.方法名(..)
修饰关键词:protected , public , private ….一般都省略不写
返回值类型:一般返回值类型用 * 号代替,表示任意的返回值都可以
方法名中的两个点:表示所带的参数的个数。
举例如下:
任意以public修饰的方法都可以 execution(public * *(..)) 任何以set开头的方法都可以 execution(* set*(..)) 任何在AccountService 这个接口下面的方法都可以 execution(* com.xyz.service.AccountService.*(..)) 任何在com.xyz.service 这个包下面的所有类的所有方法都可以 execution(* com.xyz.service.*.*(..)) 任何在com.xyz.service 这个包以及整个包下面的所有子包的所有类的所有方法都可以 execution(* com.xyz.service..*.*(..)) ..代表这个包及这个包下面的所有子包 |
Spring中的5种通知类型及参数
前置通知:在目标方法开始之前进行执行的通知
参数:JoinPoint
后置通知:在目标方法执行之后,无论是否发生异常,都进行执行的通知
参数:JoinPoint
返回通知:在目标方法正常结束时,才执行的通知
参数:JoinPoint,Object
异常通知:在目标方法出现异常时才会进行执行的通知
参数:JoinPoint,Exception
环绕通知:在目标方法执行之前、 之后都会执行的通知
参数:ProceedingJoinPoint(必须有)
AOP基于注解方式的实现
xml配置中开启spring注解扫描及开启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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
<!-- 开启spring的注解驱动 -->
<context:component-scan base-package="spring.aop.annotation"></context:component-scan> <!-- 开启aop的自动代理:使用注解实现AOP,这个必须配置 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
定义接口及接口实现类
此处省略,同xml配置方式相同
通过注解的方式定义切面类
/**
* 切面
*/
@Component
@Aspect
public class UserAspect {
//前置通知
@Before(value = "execution(* *.add*(..))")
public void beforeAdvice(JoinPoint jp){
String name = jp.getSignature().getName();
System.out.println("前置通知的切入点的方法名:" + name);
System.out.println("前置通知...");
} //后置通知
@After(value = "execution(* *.delete*(..))")
public void afterAdvice(JoinPoint jp){
String name = jp.getSignature().getName();
System.out.println("后置通知的切入点的方法名:" + name);
System.out.println("后置通知...");
} //返回通知
@AfterReturning(value = "execution(* *.update*(..))",returning="result")
public void afterReturningAdvice(JoinPoint jp,Object result){
String name = jp.getSignature().getName();
System.out.println("返回通知的切入点的方法名:" + name);
System.out.println(result);
System.out.println("返回通知...");
} //异常通知
@AfterThrowing(value = "execution(* *.getById*(..))",throwing="ex")
public void exceptionAdvice(JoinPoint jp,Exception ex){
String name = jp.getSignature().getName();
System.out.println("异常通知的切入点的方法名:" + name);
System.out.println(ex.getMessage());
System.out.println("异常通知...");
} //环绕通知
@Around(value = "execution(* *.batch*(..))")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("环绕通知前...");
Object result = pjp.proceed();
String name = pjp.getSignature().getName();
System.out.println("环绕通知的切入点的方法名:" + name);
System.out.println("环绕通知后...");
return result;
}
}
测试
/**
* 注解形式的AOP的单元测试类
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-aop-annotation.xml")
public class AnnotationAopTest {
@Autowired
private UserService userService; @Test
public void test(){
//注解:前置通知的测试
// userService.add(); //后置通知的测试
// userService.delete(); //返回通知
// userService.update(); //异常通知
// userService.getById(); //环绕通知
userService.batch();
}
}
最新文章
- hdu 1272 小希的迷宫
- JSON-SCHEMA
- 《javascript高级程序设计》第四章 Variables,scope,and memory
- PHP数组的操作
- HDU4763 - Theme Section(KMP)
- IOS开发之UINavigationBar
- Silverlight 图表下载到Excel文件中
- httpClient download file(爬虫)
- 双11电商剁手节,最全的H5互动营销案例合集
- linux系统光盘开机自动挂载-配置本地yum源
- ethereum/EIPs-191 Signed Data Standard
- CentOS7 搭建LVS+keepalived负载均衡
- Kubernetes学习之路(二十三)之资源指标和集群监控
- 移动option标签
- sam9260 adc module
- python nose测试框架全面介绍三
- codeforces 782B - The Meeting Place Cannot Be Changed
- HDU--4768
- type=";submit";表单提交理解
- 程序入口函数和glibc及C++全局构造和析构