spring03-AOP思想和SSM集成

本文深入探讨了AOP(面向切面编程)的核心思想,解释了如何通过AOP解决业务方法中日志记录、权限检查等问题,避免代码重复,提高项目可维护性。介绍了AOP的重要术语,如Joinpoint、Pointcut、Advice、Aspect等,并展示了如何使用Spring AOP进行事务配置,包括XML和注解方式。此外,还提供了详细的项目源码示例,涵盖了Maven项目搭建、依赖配置、数据库操作、AOP事务配置等全过程。

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"));
    }
}
06-22
### 得物技术栈及开发者文档分析 得物作为一家专注于潮流商品的电商平台,其技术栈和开发者文档主要围绕电商平台的核心需求展开。以下是对得物技术栈及相关开发资源的详细解析: #### 1. 技术栈概述 得物的技术栈通常会涵盖前端、后端、移动应用开发以及大数据处理等多个领域。以下是可能涉及的主要技术栈[^3]: - **前端开发**: 前端技术栈可能包括现代框架如 React 或 Vue.js,用于构建高效、响应式的用户界面。此外,还会使用 Webpack 等工具进行模块化打包和优化。 - **后端开发**: 后端技术栈可能采用 Java Spring Boot 或 Node.js,以支持高并发和分布式架构。数据库方面,MySQL 和 Redis 是常见的选择,分别用于关系型数据存储和缓存管理。 - **移动应用开发**: 得物的移动应用开发可能基于原生技术(如 Swift/Kotlin)或跨平台框架(如 Flutter)。这有助于确保移动端应用的性能和用户体验一致性。 - **大数据云计算**: 在大数据处理方面,得物可能会使用 Hadoop 或 Spark 进行数据挖掘和分析。同时,依托云服务提供商(如阿里云或腾讯云),实现弹性扩展和资源优化。 #### 2. 开发者文档分析 类似于引用中提到的 Adobe 开发者文档模板[^2],得物也可能提供一套完整的开发者文档体系,以支持内部团队协作和外部开发者接入。以下是开发者文档可能包含的内容: - **API 文档**: 提供 RESTful API 或 GraphQL 的详细说明,帮助开发者快速集成得物的功能模块,例如商品搜索、订单管理等。 - **SDK 集成指南**: 针对不同平台(如 iOS、Android 或 Web)提供 SDK 下载和集成教程,简化第三方应用的开发流程。 - **技术博客**: 分享得物在技术实践中的经验成果,例如如何优化图片加载速度、提升应用性能等。 - **开源项目**: 得物可能将部分技术成果开源,供社区开发者学习和贡献。这不仅有助于提升品牌形象,还能吸引更多优秀人才加入。 #### 3. 示例代码 以下是一个简单的示例代码,展示如何通过 RESTful API 调用得物的商品搜索功能(假设接口已存在): ```python import requests def search_items(keyword, page=1): url = "https://api.dewu.com/v1/items/search" headers = { "Authorization": "Bearer YOUR_ACCESS_TOKEN", "Content-Type": "application/json" } params = { "keyword": keyword, "page": page, "size": 10 } response = requests.get(url, headers=headers, params=params) if response.status_code == 200: return response.json() else: return {"error": "Failed to fetch data"} # 调用示例 result = search_items("Air Jordan", page=1) print(result) ``` 此代码片段展示了如何通过 Python 请求得物的 API,并获取指定关键词的商品列表。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小云很优秀

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

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

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

打赏作者

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

抵扣说明:

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

余额充值