spring03-AOP思想和SSM集成

AOP思想和重要术语

需求问题

在开发中,为了给业务方法中增加日志记录,权限检查,事务控制等功能,此时我们需要去修改业务方法代码,考虑到代码的重用性,我们可以考虑使用OOP的继承或组合关系来消除重复,但是无论怎么样,我们都会在业务方法中纵向地增加这些功能方法的调用代码。此时,既不遵循开闭原则,也会为后期系统的维护带来很大的麻烦。(即不管怎样都得修改到原来的代码)

为了解决该问题,OOP 思想是不行了,得使用 AOP 思想。

AOP是什么

AOP(Aspect Oriented Programming),是面向切面编程的技术,把一个个的横切关注点放到某个模块中去,称之为切面。那么每一个的切面都能影响业务的某一种功能,切面的目的就是功能增强,如日志切面就是一个横切关注点,应用中许多方法需要做日志记录的只需要插入日志的切面即可。(动态代理就可以实现 AOP),这种面向切面编程的思想就是 AOP 思想,不修改现有代码的前提下给某些类中方法添加功能,符合开闭原则,提供项目可维护性。

把业务方法中与业务无关的操作抽离到不同的对象中,最后使用动态代理的方式组合起来,动态地为类增加功能。

AOP术语

Joinpoint:连接点,一般指需要被增强的方法。where:去哪里做增强。

Pointcut:切入点,哪些包中的哪些类中的哪些方法,可认为是连接点的集合。where:去哪些地方做增强。

Advice:增强,当拦截到 Joinpoint 之后,在方法执行的什么时机(when)做什么样(what)的增强。根据时机分为:前置增强、后置增强、异常增强、最终增强、环绕增强。

Aspect:切面,Pointcut + Advice,去哪些地方 + 在什么时候 + 做什么增强。

Target:被代理的目标对象。

Weaving:织入,把 Advice 加到 Target 上之后,创建出 Proxy 对象的过程。

Proxy:一个类被 AOP 织入增强后,产生的代理类。

AspectJ切入点Pointcut表达式

AspectJ 是一个面向切面的框架,它扩展了Java 语言(即使用 Java 对 AOP 进行了实现)。

AspectJ切入点语法

怎么表示Pointcut,即怎么表示哪些包中的哪些类中的哪些方法?AspectJ提供了表示切入点的语法

  1. 切入点语法通配符

    *:匹配任何部分,只能表示一个单词

    … : 可用于全限定名中和方法参数中,分别表示子包和 0 到 N 个参数

  2. 切入点语法案例

    execution(* cn.wolfcode.ssm.service.impl.*ServiceImpl.*(..))
    

    注意第一个星符号后面有空格。

使用XML配置AOP

需求

想给业务方法加模拟的事务功能,又不想修改原来的代码

使用AOP

  • 添加依赖

    <dependency>
    	<groupId>org.aspectj</groupId>
    	<artifactId>aspectjweaver</artifactId>
    	<version>1.8.13</version>
    </dependency>
    
  • XML文件添加AOP约束,编写配置

  • 编写单元测试

变更使用CGLIB

Spring AOP 不做配置的话且目标对象实现接口的话,默认使用 JDK 的动态代理。若想强制使用 CGLIB,则在applicationContext.xml配置如下:

<aop:config proxy-trage-calss="true">

使用注解配置AOP

对比XML配置来使用注解的方式来配置

变更使用CGLIB

在applicationContext.xml配置如下

<aop:aspectj-autoproxy proxy-trage-calss="true">

集成

集成作用及本质

使用框架,在别人的基础上开发,提高效率;

集成MyBatis和业务层,即业务对象、Mapper对象等都交由Spring容器管理,使用Spring IoC 和DI来完成对象创建及其属性注入,后面再使用AOP来配置事务。

项目搭建熟练集成

新建项目添加依赖
利用 IoC DI
关联 db.properties
配置数据源 DruidDataSource
配置 SqlSessionFactory bean SqlSessionFactoryBean
批量配置 Mapper 接口的实现类对象 MapperScannerConfigurer
配置业务对象
利用 AOP 配置事务
XML(最低要求拷贝能改)
注解配置
配置事务管理器,给其注入数据源 DataSourceTransactionManager
配置事务注解解析器,关联事务管理器
在想加事务功能方法或者类上添加注解 @Transactional

Transactional注解使用

Transactional注解可以贴在接口或实现类上,即类或接口上的事务的配置是通用与整个类或接口的的方法;而也可以贴方法上,即方法上的的事务的配置仅限于被贴的方法。

若想强制使用CGLIB动态代理,则修改tx:annotation-drive上的属 proxy-target-class修改为true即可。

项目源码

需求

新建Maven项目,打包方式是war,为后面项目做铺垫。需求:做个转账功能。

mop.xml 依赖和插件

  <dependencies>
    <!--    web 项目相关的-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.16.20</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.0.1</version>
    </dependency>
    <!--    spring 相关-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.0.8.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.0.8.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.0.8.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.13</version>
    </dependency>
    <!--    数据库相关-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.45</version>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.9</version>
    </dependency>
    <!-- MyBatis 相关-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.4.5</version>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.12</version>
    </dependency>
    <!-- Spring集成MyBatis -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.1</version>
    </dependency>
    <!--页面标签-->
    <dependency>
      <groupId>org.apache.taglibs</groupId>
      <artifactId>taglibs-standard-spec</artifactId>
      <version>1.2.5</version>
    </dependency>
    <dependency>
      <groupId>org.apache.taglibs</groupId>
      <artifactId>taglibs-standard-impl</artifactId>
      <version>1.2.5</version>
    </dependency>
  </dependencies>

  <build>
    <finalName>ssm</finalName>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.apache.tomcat.maven</groupId>
          <artifactId>tomcat7-maven-plugin</artifactId>
          <version>2.1</version>
          <configuration>
            <port>8080</port>
            <path>/</path>
            <uriEncoding>UTF-8</uriEncoding>
          </configuration>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <configuration>
            <source>1.8</source>
            <target>1.8</target>
            <encoding>UTF-8</encoding>
          </configuration>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>

数据库及实体对象

CREATE TABLE `account` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `balance` decimal(10,2) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@Setter
@Getter
public class Account {
	private Long id;
	private BigDecimal balance;
}

Mapper接口和Mapper配置文件

public interface AccountMapper {
    void addBalance(@Param("inId")Long inId, @Param("amount") BigDecimal amount);
    void subtractBalance(@Param("outId") Long outId, @Param("amount")BigDecimal amount);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.wolfcode.mapper.AccountMapper">
    <update id="addBalance">
       UPDATE account SET balance = balance + #{amount} WHERE id = #{inId}
   </update>
    <update id="subtractBalance">
       UPDATE account SET balance = balance - #{amount} WHERE id = #{outId}
   </update>
</mapper>

applicationContext.xml 配置

<?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:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
    <!--关联db.properties-->
    <context:property-placeholder location="db.properties"/>
    <!--配置dataSource-->
    <bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource" init-method="init" destroy-method="close">
        <property name="driverClassName" value="${db.driverClassName}"/>
        <property name="url" value="${db.url}"/>
        <property name="username" value="${db.username}"/>
        <property name="password" value="${db.password}"/>
    </bean>
    <!--配置sqlSessionFactory对象-->
    <bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">
        <!--数据源-->
        <property name="dataSource" ref="dataSource"/>
        <!--配置别名-->
        <property name="typeAliasesPackage" value="cn.wolfcode"/>
        <!--mapper 配置文件-->
        <property name="mapperLocations" value="classpath:cn/wolfcode/mapper/*Mapper.xml"/>
    </bean>

    <!--配置Mapper接口扫描器-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="cn.wolfcode.mapper"/>
    </bean>
    <!--Ioc ID 注解解析器-->
    <context:component-scan base-package="cn.wolfcode.service.impl"/>

    <!--配置事务管理器-->
    <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--事务注解解析器-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

service实现类

@Service
@Transactional
public class AccountServiceImpl implements IAccountService {
    @Autowired
    private AccountMapper accountMapper;

    @Override
    public void transfer(Long outId, Long inId, BigDecimal amount) {

        accountMapper.addBalance(inId,amount);
        int a = 1/0;
        accountMapper.subtractBalance(outId,amount);
    }
}

单元测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AccountServiceTest {

    @Autowired
    private IAccountService accountService;
    @Test
    public void transfer() {
        accountService.transfer(1L,2L,new BigDecimal("10"));
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小云很优秀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值