SpringAOP的实现原理

本文介绍了AOP(面向切面编程)的概念,其在软件开发中的优势,以及如何在Spring中使用AOP实现事务管理,包括XML配置和注解驱动的方式。重点讲解了通知类型、切面、织入和SpringAOP的关键术语及其实例应用。
摘要由CSDN通过智能技术生成

什么是AOP

AOP为Aspect Oriented Programming的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理实现程序功能饿统一维护的一种技术

AOP是OOP的延续,是软件开发中的一个热点,也是一个Spring框架中的一个重要内容,是函数式编程的一种衍生范型,利用AOP可以对业务逻辑的各种部分进行隔离,从而使得业务逻辑各部分之间的耦合读降低,提高程序的可重用性,同时提高了开发效率

功能:

        1.事务   2.日记录   3.权限控制

AOP的优势

        优势:减少重复代码,提高开发效率,并且便于维护

AOP关键术语

通知类型:

        AOP将抽取出来的共性功能称为通知,通知类型:以通知在上下文中的具体位置作为划分

                前置通知:Before

                后置通知:After

                返回通知:After-returning

                异常通知:After-throwing

                环绕通知:Around

Spring AOP

①. AOP 在Spring中的作用

提供声明式事务;允许用户自定义切面

②. AOP 的基本概念

横切关注点:跨越应用程序多个模块的方法或功能。即与我们业务逻辑无关,但需要我们关注的部分就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 ....

  • Aspect(切面):横切关注点被模块化的特殊对象。通常是一个类,里面可以定义切入点和通知
  • Weaving(织入):把切面(aspect)连接到其它的应用程序类型或者对象上,并创建一个被通知(advised)的对象。 这些可以在编译时,类加载时和运行时完成。Spring和其它纯Java AOP框架一样,在运行时完成织入
  • Advice(通知):AOP在特定的切入点上执行的增强处理,是切面必须要完成的工作,也是类中的一个方法
  • Target(目标):被通知对象
  • AOP(代理):AOP框架创建的对象,代理就是目标对象的加强。Spring中的 AOP 代理可以是 JDK 动态代理,也可以是 CGLIB 代理,前者基于接口,后者基于子类
  • JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用
  • Pointcut(切入点):就是带有通知的连接点,与切入点匹配的执行点

③. 使用Spring实现Aop

以下是用AOP实现事务(Transaction)

方式一(xml版):

<!-- 获取数据源-->
    <bean id="data" class="com.alibaba.druid.pool.DruidDataSource" >
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/javaee230809db?serverTimezone=UTC" />
        <property name="username" value="root" />
        <property name="password" value="123456" />
    </bean>



    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="data" />
    </bean>

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.apesource.dao" />
    </bean>

    <!--扫描注入对象的注解-->
    <context:component-scan base-package="com.apesource"></context:component-scan>




    <!-- 配置一个事务管理器 -->
    <bean id="tm" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 注入DataSource -->
        <property name="dataSource" ref="data"></property>
    </bean>

    <!-- 事务的配置 -->
    <tx:advice id="txAdvice" transaction-manager="tm">
        <!-- 指定方法名称:是业务核心方法
            read-only:是否是只读事务。默认false,不只读。
            isolation:指定事务的隔离级别。默认值是使用数据库的默认隔离级别。
            propagation:指定事务的传播行为。
            timeout:指定超时时间。默认值为:-1。永不超时。
            rollback-for:用于指定一个异常,当执行产生该异常时,事务回滚。产生其他异常,事务不回滚。没有默认值,任何异常都回滚。
            no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时,事务回滚。没有默认值,任何异常都回滚。
        -->
        <tx:attributes>
            <tx:method name="*" read-only="false" propagation="REQUIRED" isolation="DEFAULT"/>
            <tx:method name="find*" read-only="true" propagation="SUPPORTS" isolation="DEFAULT"/>
        </tx:attributes>
    </tx:advice>


    <!-- 配置aop -->
    <aop:config>
        <!-- 配置切入点表达式 -->
        <aop:pointcut expression="execution(* com.apesource.service.*.*(..))" id="pt1"/>
        <!-- 在aop:config标签内部:建立事务的通知和切入点表达式的关系 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"/>
    </aop:config>

方式二(注解版):

 <bean id="data" class="com.alibaba.druid.pool.DruidDataSource" >
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/javaee230809db?serverTimezone=GMT" />
        <property name="username" value="root" />
        <property name="password" value="123456" />
    </bean>


    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="data" />
    </bean>


    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.apesource.dao" />
    </bean>

    <!--扫描注入对象的注解-->
    <context:component-scan base-package="com.apesource"/>



    <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
        <property name="dataSource" ref="data"></property>
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
/**
     * 转账业务
     * */
@Override
@Transactional(readOnly = false,propagation = Propagation.REQUIRED)
public void transfer(String sourceName, String targetName, int money) {
    //2.1查询转账人与被转账人的信息
    Account sourceAccount = dao.findAccountByName(sourceName);
    Account targetAccount = dao.findAccountByName(targetName);
    //2.2开始转账
    sourceAccount.setAmoney(sourceAccount.getAmoney()-money);
    targetAccount.setAmoney(targetAccount.getAmoney()+money);
    //2.3修改数据库
    dao.updateAccountById(sourceAccount);
    //模拟转账事故
    int a = 10/0;
    dao.updateAccountById(targetAccount);
}

  • 16
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值