AOP(spring中)

Q为什么需要切面

A:事务模块不仅仅是为特定业务提供服务,还要处理系统辅组功能(日志记录,安全管理)。这时候我们就需要aop,将核心代码以及次要代码分隔开。这样做有两个好处:1.关注点代码都集中于一处,而不是分布在多代码,方便管理2.其次,服务模块更加简洁,因为他们只用关注功能逻辑的代码。以后需要添加辅助功能时候,也不会干涉到原本的类。

    然后就会在运行期间,根据切入点动态织入目标对象中,生成代理对象。

AOP几个专属名词解释

通知:就是切面需要额外执行的逻辑

  1. 前置通知:在目标方法调用前
  2. 后置通知:在目标方法调用完成之后,但是没有执行渲染
  3. 异常通知
  4. 环绕通知

连接点:可以插入切点的地方

切点:插入切面的地方

切面:what(通知内容) when(通知时间) where(切点)

织入:切面在指定的连接点中,织入到目标对象中,目标对象的生命周期中有多个点可以进行织入:

编译期间:切面在目标类编译时被织入,这种方式需要特殊的编译器。AspectJ的织入编译就是这样的

类加载期:切面在目标类加载到JVM时候被织入。这种方式需要特殊的类加载(class loader),它可以在目标类被引用之前强加入目标类的字节码。

运行期:切面在应用运行时的某一个时刻织入,一般情况下,在织入切面时候,AOP容器会为目标对象生成一个代理对象。springaop就是采用运行期。

 

定义切面的类 也是需要注册到IOC容器中,运行期间调用目标类时候,首先判断是否需要将切面织入到目标类中,如果不需要直接返回目标类,否则返回代理类。

切面织入到目标类中,通过动态代理生成代理类,放置在springaop容器中。

 

以下转自:https://www.cnblogs.com/cndota/p/6129244.html

简单的记录一下spring aop的一个示例

基于两种配置方式:

      基于xml配置

      基于注解配置

这个例子是模拟对数据库的更改操作添加事物

其实并没有添加,只是简单的输出了一下记录

 

首先看下整个例子的目录图

  

全部代码就不贴了,数目有点多,不过很简单,看一部分就能够明白

 

第一种配置方式

  基于xml方式配置

  首先将service,dao注册到spring容器

  

  配置一下扫描包还是很方便的

  接下来看下service

  

 

 1 package com.yangxin.core.service.impl;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.stereotype.Service;
 5 
 6 import com.yangxin.core.dao.UserDao;
 7 import com.yangxin.core.pojo.User;
 8 import com.yangxin.core.service.UserService;
 9 
10 @Service
11 public class UserServiceImpl implements UserService {
12 
13     @Autowired
14     private UserDao userDao;
15     
16     @Override
17     public void addUser(User user) {
18         userDao.insertUser(user);
19         System.out.println("添加成功");
20     }
21 
22     @Override
23     public void deleteUser(String name) {
24         userDao.deteleUser(name);
25         System.out.println("删除成功");
26     }
27 
28 }

 

要做的事情很简单,插入一条数据,删除一条数据

 

接下来看下切面代码

 

 1 package com.yangxin.core.transaction;
 2 
 3 import org.aspectj.lang.ProceedingJoinPoint;
 4 
 5 import com.yangxin.core.pojo.User;
 6 
 7 public class TransactionDemo {
 8     
 9     //前置通知
10     public void startTransaction(){
11         System.out.println("begin transaction ");
12     }
13     
14     //后置通知
15     public void commitTransaction(){
16         System.out.println("commit transaction ");
17     }
18     
19     //环绕通知
20     public void around(ProceedingJoinPoint joinPoint) throws Throwable{
21         System.out.println("begin transaction");
22         
23         joinPoint.proceed();
24         
25         System.out.println("commit transaction");
26     }
27     
28 }

 

然后看下这个切面在applicationContext.xml中是如何配置的

 

复制代码

  <aop:config>
          <aop:pointcut expression="execution(* com.yangxin.core.service.*.*.*(..))" id="p1" />
  
          <aop:aspect ref = "transactionDemo">
          
          <aop:before method="startTransaction" pointcut-ref="p1" />
          
          <aop:after-returning method="commitTransaction" pointcut-ref="p1"/>
         
         </aop:aspect>
     </aop:config>

 

这里没有演示环绕通知

好了,运行测试代码

控制台输出如下

  begin transaction

  添加成功

  commit transaction

  begin transaction

  删除成功

  commit transaction

现在来测试一下环绕通知

修改一下applicationContext.xml中的配置切面那一部分

修改后的代码

 

 <aop:config>
         <aop:pointcut expression="execution(* com.yangxin.core.service.*.*.*(..))" id="p1" />
 
         <aop:aspect ref = "transactionDemo">
         
         <aop:around method="around" pointcut-ref="p1"/>
         
         </aop:aspect>
     </aop:config>

 

运行测试代码

输出如下

begin transaction
添加成功
commit transaction
begin transaction
删除成功
commit transaction

 

好了,现在贴下如何用注解的方法

贴下基于注解的切面的代码

 

  package com.yangxin.core.transaction;
  
  import org.aspectj.lang.ProceedingJoinPoint;
  import org.aspectj.lang.annotation.AfterReturning;
  import org.aspectj.lang.annotation.Around;
  import org.aspectj.lang.annotation.Aspect;
  import org.aspectj.lang.annotation.Before;
  import org.aspectj.lang.annotation.Pointcut;
 
 @Aspect
 public class TransactionDemo2 {
     
     @Pointcut(value="execution(* com.yangxin.core.service.*.*.*(..))")
     public void point(){
         
     }
    
     @Before(value="point()")
     public void before(){
         System.out.println("transaction begin");
     }
     
     @AfterReturning(value = "point()")
     public void after(){
         System.out.println("transaction commit");
     }
     
     @Around("point()")
     public void around(ProceedingJoinPoint joinPoint) throws Throwable{
         System.out.println("transaction begin");
         joinPoint.proceed();
         System.out.println("transaction commit");
         
     }
}

 

在applicationContext.xml中配置

1 <bean id = "transactionDemo2" class = "com.yangxin.core.transaction.TransactionDemo2" />
1 <aop:aspectj-autoproxy />

测试步骤和以上一致,这里就不贴了

 

完毕

 

记一下使用javaConfig配置方式的一些坑

 

以上 切面 不管是基于注解的还是基于xml配置的   这里把切面加载到容器中都是用xml配置bean的方式

 

如果用javaConfig方式的话

 

需要在配置类上加上 @EnableAspectJAutoProxy 注解

 

然后如果使用扫包的方式配置切面bean的话

切面上除了要加上@Aspect注解标识为这是一个切面bean之外

还需要在上面加上@component这个注解

很急很关键

排错的时候只关注切点表达式的问题了

当时一直在找切点表达式的问题

其实这个表达式写的是没有问题的

是配置切面bean的时候出的问题

深坑

 

切面也是属于ioc容器的,@EnableAspectJAutoProxy true默认是cglib动态代理

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值