Spring—AOP(简单介绍)


前言

AOP定义:面向切面编程
AOP的使用只存在于一些特定的场合(具有横切逻辑的应用场合),横切逻辑这个解释可能比较抽象,咱们说得再具体一点,AOP可以用于事务管理,日志管理,性能监测,权限校验等地方
Spring的AOP是通过代理模式实现的。实际生活中常见的代理场景如:房屋中介、黄牛售卖火车票。
代理分为静态代理和动态代理,Spring使用动态代理来完成AOP。
生成动态代理的两种方式:JDK动态代理(只支持实现接口的类)、CGLIB动态代理


一、XML版实现AOP

通过一个简单的案例演示AOP

如下为了实现用户注册和管理员注册,需要开启事务、关闭事务等大量重复的代码

public class UserServiceImpl implements IUserService {
    public void save() {
        try {
            System.out.println("开启事务");
            System.out.println("用户注册");
            System.out.println("提交事务");
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("回滚事务");
        }finally {
            System.out.println("关闭事务");
        }
    }
}
public class DeptServiceImpl implements IDeptService{
    public void save() {
        try {
            System.out.println("开启事务");
            System.out.println("管理员注册");
            System.out.println("提交事务");
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("回滚事务");
        }finally {
            System.out.println("关闭事务");
        }
    }
}

使用AOP简化上面的代码

将事务代码抽取成一个事务方法的类

public class TxManager {

    public void start(){
        System.out.println("开启事务");
    }

    public void conmit(){
        System.out.println("提交事务");
    }

    public void rollback(Throwable throwable){
        System.out.println("回滚事务,错误信息是:"+throwable);
    }

    public void close(){
        System.out.println("关闭事务");
    }
}

业务类只留下自己特有的方法即可

public class UserServiceImpl implements IUserService {
    public void save() {
        System.out.println("用户注册");
    }
}

配置SpringTest-Context.xml

如果有2个以上的切面增强,Spring可能会造成增强乱序

<bean id="userService" class="cn.itsource._03_aop.service.impl.UserServiceImpl"/>

    <bean id="txManager" class="cn.itsource._03_aop.TxManager"/>

    <!--开启aop-->
    <aop:config>
        <!--pointcut:切点,id:随便取,expression:要切的方法-->
        <!--第一个*表示所有的返回值
        第二个*表示所有的以I开头,service结尾的类
        两个..表示所有的参数,不同形参的save-->
        <aop:pointcut id="userPoincut" expression="execution(* cn.itsource._03_aop.service.I*Service.save(..))"/>

        <!--aspect:切面-->
        <aop:aspect ref="txManager">
            <!--在业务代码之前-->
            <aop:before method="start" pointcut-ref="userPoincut"/>
            <!--在业务代码之后-->
            <aop:after-returning method="conmit" pointcut-ref="userPoincut"/>
            <!--业务代码出现异常后 throwing:配置错误信息-->
            <aop:after-throwing method="rollback" pointcut-ref="userPoincut" throwing="throwable"/>
            <!--最终执行-->
            <aop:after method="close" pointcut-ref="userPoincut"/>
            
    </aop:config>

编写配置测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class SpringTest {

    @Autowired
    private IUserService service;

    @Test
    public void test(){
        service.save();
    }
}

使用环绕增强

环绕增强是我们自己来控制切面的顺序,就不会出现乱序

public class TxManager {
    /**
     *环绕增强
     * @param joinPoint
     *
     * ProceedingJoinPoint能获取业务类
     */
    public void around(ProceedingJoinPoint joinPoint){
        try {
            start();
            //反射机制获取业务方法
            joinPoint.proceed();
            conmit();
        }catch (Throwable e){
            rollback(e);
        }finally {
            close();
        }
    }
}

配置xml

   <!--开启aop-->
    <aop:config>
        <!--pointcut:切点,id:随便取,expression:要切的方法-->
        <!--第一个*表示所有的返回值
        第二个*表示所有的以I开头,service结尾的类
        两个..表示所有的参数,不同形参的save-->
        <aop:pointcut id="userPoincut" expression="execution(* cn.itsource._03_aop.service.I*Service.save(..))"/>

        <!--aspect:切面-->
        <aop:aspect ref="txManager">
 
          <!--around:环绕切面,不会发生顺序问题。上面的配置多个切面方法spring可能发生顺序问题-->
          <aop:around method="around" pointcut-ref="userPoincut"/>

        </aop:aspect>
    </aop:config>

测试方法和上面的一样,但是需要注意,环绕增强和普通顺序增强不能同时出现,会重复执行

二、注解版实现AOP

实现类

@Service
public class UserServiceImpl implements IUserService {
    public void save() {
        System.out.println("用户注册");
    }
}

配置SpringTest-Context.xml

    <!--开启注解扫描-->
    <context:component-scan base-package="cn.itsource._04_aopanno"/>
    <!--支持aop注解-->
    <aop:aspectj-autoproxy/>

事务类,普通顺序增强的注解实现,这种方式也是可能会乱序

@Component  //声明bean
@Aspect    //声明该类是切面类
public class TxManager {

    //配置切点,通过一个空方法加注解实现,注解里的配置和xml的一样
    @Pointcut("execution(* cn.itsource._04_aopanno.service.I*Service.save(..))")
    public void poincut(){}

    @Before("poincut()")
    public void start(){
        System.out.println("开启事务");
    }

    @AfterReturning("poincut()")
    public void conmit(){
        System.out.println("提交事务");
    }

    @AfterThrowing(pointcut = "poincut()",throwing = "throwable")
    public void rollback(Throwable throwable){
        System.out.println("回滚事务,错误信息是:"+throwable);
    }

    @After("poincut()")
    public void close(){
        System.out.println("关闭事务");
    }
}

环绕增强,由于自己配置增强的顺序,所以不会出现乱序

@Component  //声明bean
@Aspect    //声明该类是切面类
public class TxManager {

    //配置切点,通过一个空方法加注解实现,注解里的配置和xml的一样
    @Pointcut("execution(* cn.itsource._04_aopanno.service.I*Service.save(..))")
    public void poincut(){}

    /**
     * @param joinPoint
     * ProceedingJoinPoint能获取业务类
     */
    @Around("poincut()")
    public void around(ProceedingJoinPoint joinPoint){
        try {
            start();
            //反射机制获取业务方法
            joinPoint.proceed();
            conmit();
        }catch (Throwable e){
            rollback(e);
        }finally {
            close();
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值