SpringAOP四种通知类型+环绕通知说明⽬录
⼀、四种常见的通知类型
注意
⼆、环绕通知
1、改动⽇志类 Logger.java
2、改动配置⽂件
分析
AOP机制之环绕通知的见解
其中有五个通知类型
SpringAOP的四种通知类型:前置通知、异常通知、后置通知、异常通知
⼀、四种常见的通知类型
给出账户的业务层接⼝ IAccountService.java,
为了便于演⽰这四种通知类型,我们就只留下了⼀个⽅法。
public interface IAccountService {
void saveAccount();
}
给出账户的业务层接⼝的实现类 AccountServiceImpl.java
public class AccountServiceImpl implements IAccountService{
@Override
public void saveAccount() {
System.out.println("执⾏了保存");
//int i=1/0;
}
}
给出⼀个⽇志类,⽤于打印⽇志
public class Logger {
/**
* 前置通知
*/
public void beforePrintLog(){
System.out.println("前置通知Logger类中的beforePrintLog⽅法开始记录⽇志了。。。");
}
/**
* 后置通知
*/
public void afterReturningPrintLog(){
System.out.println("后置通知Logger类中的afterReturningPrintLog⽅法开始记录⽇志了。。。");
}
spring roll怎么读/**
* 异常通知
*/
public void afterThrowingPrintLog(){
System.out.println("异常通知Logger类中的afterThrowingPrintLog⽅法开始记录⽇志了。。。");
}
/
**
* 最终通知
*/
public void afterPrintLog(){
System.out.println("最终通知Logger类中的afterPrintLog⽅法开始记录⽇志了。。。");
}
}
给出配置信息l
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="/schema/beans"
xmlns:xsi="/2001/XMLSchema-instance"
xmlns:aop="/schema/aop"
xsi:schemaLocation="/schema/beans
/schema/beans/spring-beans.xsd
/schema/aop
/schema/aop/spring-aop.xsd">
<!-- 配置srping的Ioc,把service对象配置进来-->
<bean id="accountService" class="service.AccountServiceImpl"></bean>
<!-- 配置Logger类 -->
<bean id="logger" class="utils.Logger"></bean>
<!--配置AOP-->
<aop:config>
<!--配置切⼊点表达式 -->
<aop:pointcut id="pt1" expression="execution(* service.AccountServiceImpl.saveAccount())"></aop:pointcut> <!--配置切⾯ -->
<aop:aspect id="logAdvice" ref="logger">
<!-- 配置前置通知:在切⼊点⽅法执⾏之前执⾏-->
<aop:before method="beforePrintLog" pointcut-ref="pt1" ></aop:before>
<!-- 配置后置通知:在切⼊点⽅法正常执⾏之后值-->
<aop:after-returning method="afterReturningPrintLog" pointcut-ref="pt1"></aop:after-returning>
<!-- 配置异常通知:在切⼊点⽅法执⾏产⽣异常之后执⾏-->
<aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"></aop:after-throwing>
<!-- 配置最终通知:⽆论切⼊点⽅法是否正常执⾏它都会在其后⾯执⾏-->
<aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after>
</aop:aspect>
</aop:config>
</beans>
注意
1)异常通知和后置通知永远只能执⾏⼀个
2)配置切⼊点表达式
此标签写在aop:aspect标签内部只能当前切⾯使⽤。
它还可以写在aop:aspect外⾯,此时就变成了所有切⾯可⽤
给出Test类
public class AOPTest {
public static void main(String[] args) {
/
/1.获取容器
ApplicationContext ac = new ClassPathXmlApplicationContext("l");
//2.获取对象
IAccountService as = (Bean("accountService");
//3.执⾏⽅法
as.saveAccount();
}
}
执⾏结果:
当我们放开AccountServiceImpl类中我们故意制造的异常 int i=1/0;时:
⼆、环绕通知
环绕通知,只需要稍稍微改变上⾯例⼦的两点即可
1、改动⽇志类 Logger.java
public class Logger {
public Object aroundPringLog(ProceedingJoinPoint pjp){
Object rtValue = null;
try{
Object[] args = Args();//得到⽅法执⾏所需的参数
System.out.println("Logger类中的aroundPringLog⽅法开始记录⽇志了。。。前置");
rtValue = pjp.proceed(args);//明确调⽤业务层⽅法(切⼊点⽅法)
System.out.println("Logger类中的aroundPringLog⽅法开始记录⽇志了。。。后置");
return rtValue;
}catch (Throwable t){
System.out.println("Logger类中的aroundPringLog⽅法开始记录⽇志了。。。异常");
throw new RuntimeException(t);
}finally {
System.out.println("Logger类中的aroundPringLog⽅法开始记录⽇志了。。。最终");
}
}
}
注意:pjp.proceed(args)会报异常,必须⽤ Throwable t,因为Exception拦不住它
2、改动配置⽂件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="/schema/beans"
xmlns:xsi="/2001/XMLSchema-instance"
xmlns:aop="/schema/aop"
xsi:schemaLocation="/schema/beans
/schema/beans/spring-beans.xsd
/schema/aop
/schema/aop/spring-aop.xsd">
<!-- 配置srping的Ioc,把service对象配置进来-->
<bean id="accountService" class="service.AccountServiceImpl"></bean>
<!-- 配置Logger类 -->
<bean id="logger" class="utils.Logger"></bean>
<!--配置AOP-->
<aop:config>
<!--配置切⼊点表达式 -->
<aop:pointcut id="pt1" expression="execution(* service.AccountServiceImpl.saveAccount())"></aop:pointcut>
<!--配置切⾯ -->
<aop:aspect id="logAdvice" ref="logger">
<!-- 配置环绕通知详细的注释请看Logger类中-->
<aop:around method="aroundPringLog" pointcut-ref="pt1"></aop:around>
</aop:aspect>
</aop:config>
</beans>
分析
spring中的环绕通知是spring框架为我们提供的⼀种可以在代码中⼿动控制增强⽅法何时执⾏的⽅式。
Spring框架为我们提供了⼀个接⼝:ProceedingJoinPoint。该接⼝有⼀个⽅法proceed(),此⽅法就相当于明确调⽤切⼊点⽅法。该接⼝可以作为环绕通知的⽅法参数,在程序执⾏时,spring框架会为我们提供该接⼝的实现类供我们使⽤。
AOP机制之环绕通知的见解
我们都知道,AOP机制的核⼼是在不修改源码的基础上对业务层⽅法的增强。
其中有五个通知类型
1、前置通知:在切⼊点⽅法之前执⾏
2、后置通知:在切⼊点⽅法之后通知
3、异常通知:在执⾏切⼊点⽅法过程中出现异常后执⾏(因此异常通知和后置通知只能执⾏⼀个)
4、最终通知:⽆论切⼊点⽅法是否正常执⾏它都会执⾏
5、环绕通知:当配置环绕通知之后,在环绕通知⾥⾯必须要明确调⽤业务层的⽅法,如果不调⽤,就会出现只出现通知,⽽不执⾏
⽅法。其中原理和动态代理是⼀样的,代码如下。
public AccountService getAccountService() {
return (AccountService) Class().getClassLoader(), Class().getInterfaces(), new InvocationHandler() { @Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
Object rtValue=null;
try {
//1、开启事务
txManager.beginTransaction();
//2、执⾏操作,整个过程像对每个⽅法进⾏了包装,并返回新的accountService对象
rtValue=method.invoke(accountService,objects);
//3、提交事务
txManagermit();
//4、返回结果
return rtValue;
}catch (Exception e){
//5、回滚事务
throw new RuntimeException(e);
}finally {
/
/6、释放连接
}
}
});
}
如果不明确调⽤业务层⽅法,就像⼀个画⽪,没有发挥本质的作⽤。
除此之外,我认为环绕通知可以代替其他的四个通知,
public Object aroundPrintLog(ProceedingJoinPoint pjp){//环绕通知是不是能够代替其他的通知
Object rtvalue=null;
try {
/
**
*这⾥的⼀切都是为都是给业务层⽅法进⾏增强,例如:把那些⽅法拿过来,然后核⼼的还是rtvalue=pjp.proceed(args),
*其他的输出只不过是为核⼼的业务层⽅法进⾏修饰
*/
Object[] Args();//得到⽅法执⾏所需的参数
System.out.println("前置通知");
rtvalue=pjp.proceed(args);//明确调⽤业务层⽅法
System.out.println("后置通知");
return rtvalue;
}catch (Throwable e){
System.out.println("异常通知");
throw new RuntimeException(e);
}finally {
System.out.println("最终通知");
}
}
这个属于典型的环绕通知,其中把输出⽅法换成相应的通知⽅法就可以(有不同观点的可以说出来⼀起讨论)。
最后,分享⼀下我学这个知识的⽅法。⽅法增强,本质上就是对源码不修改的情况下进⾏⽅法的加⼯。就好像烤⽺⾁串⼀样,其中的核⼼就是⽺⾁,就像公司给你的业务层⽅法(这个是不让修改的)。在给顾客使⽤前,收先对⽺⾁进⾏刷油、烤、撒料⼀系列过程,这⼀过程就是我们对业务层⽅法的增强,使业务层的功能更加健壮,对应的烧烤也就是更美味。核⼼的⼀点就是正确调⽤业务层的⽅法,不管在哪类通知中,都能对业务层⽅法进⾏正确、有效地增强
以上为个⼈经验,希望能给⼤家⼀个参考,也希望⼤家多多⽀持。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论