欢迎光临
我们一直在努力

Spring 核心知识点全解析(续)

四、Spring AOP(面向切面编程)- 核心重点

4.1 AOP 解决的问题

传统开发中,日志、事务、权限等通用功能会嵌入业务代码,导致:

  • 代码冗余:每个业务方法都要写重复的通用逻辑;
  • 维护困难:修改通用逻辑需改动所有业务方法。

示例问题代码:

@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;

public void addUser(){
// 日志逻辑(冗余)
System.out.println("方法开始时间:"+new Date());
userDao.addUser();
System.out.println("方法结束时间:"+new Date());
}
}

4.2 AOP 核心概念

概念说明
切面(Aspect) 通用功能模块(如日志、事务)
连接点(JoinPoint) 业务方法(如 addUser、deleteUser)
切入点(Pointcut) 要增强的连接点(指定哪些方法需要增强)
通知(Advice) 增强的具体逻辑(如前置日志、后置日志)
目标对象(Target) 被增强的业务对象(如 UserServiceImpl)
代理对象(Proxy) Spring 创建的增强后的对象

4.3 AOP 通知类型

通知类型执行时机
前置通知(Before) 目标方法执行前
后置通知(AfterReturning) 目标方法正常执行后
异常通知(AfterThrowing) 目标方法抛出异常后
最终通知(After) 目标方法执行完毕(无论是否异常)
环绕通知(Around) 目标方法执行前后均可增强(最灵活)

4.4 基于 XML 的 AOP 配置(实战)

步骤 1:引入 AOP 依赖

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>

步骤 2:编写切面类(日志功能)

public class LogAspect {
// 前置通知
public void beforeLog(){
System.out.println("方法开始时间:" + new Date());
}

// 后置通知
public void afterLog(){
System.out.println("方法结束时间:" + new Date());
}
}

步骤 3:配置 AOP

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">

<!– 目标对象 –>
<bean id="userDao" class="com.hg.dao.UserDaoImpl"></bean>
<bean id="userService" class="com.hg.service.UserServiceImpl" autowire="byType"></bean>

<!– 切面类 –>
<bean id="logAspect" class="com.hg.aspect.LogAspect"></bean>

<!– AOP配置 –>
<aop:config>
<!– 切入点:指定增强的方法(execution表达式) –>
<aop:pointcut id="pt" expression="execution(* com.hg.service.*.*(..))"/>
<!– 切面:关联切入点和通知 –>
<aop:aspect ref="logAspect">
<aop:before method="beforeLog" pointcut-ref="pt"/>
<aop:after method="afterLog" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
</beans>

步骤 4:测试

public class Client {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = ac.getBean("userService", UserService.class);
userService.addUser();
}
}

4.5 基于注解的 AOP 配置

步骤 1:开启 AOP 注解支持

<context:component-scan base-package="com.hg"></context:component-scan>
<!– 开启AOP注解 –>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

步骤 2:注解实现切面

@Component
@Aspect // 标记为切面类
public class LogAspect {
// 切入点表达式
@Pointcut("execution(* com.hg.service.*.*(..))")
public void pt(){}

// 前置通知
@Before("pt()")
public void beforeLog(){
System.out.println("方法开始时间:" + new Date());
}

// 后置通知
@After("pt()")
public void afterLog(){
System.out.println("方法结束时间:" + new Date());
}
}

五、总结

  • IOC:核心是控制反转,将对象创建权交给 Spring 容器,通过 DI 依赖注入解决对象依赖问题,支持 XML 和注解两种配置方式;
  • AOP:核心是面向切面,将通用功能(日志、事务)与业务逻辑解耦,通过通知和切入点实现无侵入式功能增强;
  • 开发建议:小型项目优先使用注解配置(简洁),大型项目可结合 XML(便于统一管理)。
  • 六、Spring 整合 MyBatis

    在实际开发中,Spring 的 IOC+AOP 常与 MyBatis 结合使用,Spring 负责对象管理和事务控制,MyBatis 负责持久层操作,二者整合可大幅简化开发,消除 MyBatis 的繁琐配置和对象管理。

    6.1 整合核心思路

  • 由 Spring 容器管理 MyBatis 的SqlSessionFactory,替代传统 MyBatis 的 mybatis-config.xml 配置;
  • 由 Spring 容器管理 MyBatis 的 Mapper 接口代理对象,通过MapperScannerConfigurer自动扫描生成;
  • 由 Spring 提供数据源(DataSource),替代 MyBatis 的数据源配置;
  • 后续通过 Spring 的事务控制管理 MyBatis 的数据库操作事务。
  • 6.2 环境搭建(Maven)

    6.2.1 引入所有依赖

    需引入 Spring、MyBatis、MyBatis-Spring 整合包、数据库驱动、连接池、日志等依赖,完整pom.xml如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.hg</groupId>
    <artifactId>Spring_MyBatis</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
    <!– Spring核心 + AOP + 事务 + JDBC –>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.8.RELEASE</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.2.8.RELEASE</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.2.8.RELEASE</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.8.RELEASE</version>
    </dependency>
    <!– MySQL驱动 –>
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
    </dependency>
    <!– Druid连接池 –>
    <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.0</version>
    </dependency>
    <!– MyBatis核心 –>
    <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.3</version>
    </dependency>
    <!– MyBatis与Spring整合包 –>
    <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.3</version>
    </dependency>
    <!– 日志 –>
    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.26</version>
    </dependency>
    <!– 测试 –>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.2.8.RELEASE</version>
    </dependency>
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    </dependency>
    </dependencies>
    <!– 配置资源扫描,让Maven加载Java目录下的XML配置文件 –>
    <build>
    <resources>
    <resource>
    <directory>src/main/java</directory>
    <includes>
    <include>**/*.xml</include>
    </includes>
    </resource>
    <resource>
    <directory>src/main/resources</directory>
    </resource>
    </resources>
    </build>
    </project>

    6.2.2 配置数据库连接信息

    在src/main/resources下创建db.properties,解耦数据库配置:

    # 数据库驱动
    jdbc.driverClass=com.mysql.jdbc.Driver
    # 数据库连接地址
    jdbc.url=jdbc:mysql://localhost:3306/spring?useUnicode=true&characterEncoding=UTF-8
    # 数据库账号
    jdbc.username=root
    # 数据库密码
    jdbc.password=123456

    6.2.3 配置 Spring 核心配置文件

    在src/main/resources下创建applicationContext.xml,核心配置数据源、SqlSessionFactory、Mapper 扫描,替代 MyBatis 的核心配置文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    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">

    <!– 1. 加载数据库配置文件 –>
    <context:property-placeholder location="classpath:db.properties" />
    <!– 2. 配置Druid数据源,由Spring管理 –>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
    <property name="driverClassName" value="${jdbc.driverClass}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
    </bean>
    <!– 3. 配置SqlSessionFactory,整合MyBatis –>
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!– 注入数据源 –>
    <property name="dataSource" ref="dataSource"/>
    <!– 配置实体类别名,指定包名即可 –>
    <property name="typeAliasesPackage" value="com.hg.pojo"/>
    </bean>
    <!– 4. 配置Mapper扫描器,自动生成Mapper代理对象并交给Spring管理 –>
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <!– 指定Mapper接口所在包 –>
    <property name="basePackage" value="com.hg.mapper"/>
    <!– 关联SqlSessionFactory –>
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>
    <!– 5. 开启Spring注解扫描,管理Service/Controller等 –>
    <context:component-scan base-package="com.hg"></context:component-scan>
    </beans>

    6.3 实战开发(用户增删改查)

    6.3.1 创建数据库表

    CREATE DATABASE IF NOT EXISTS spring;
    USE spring;
    CREATE TABLE IF NOT EXISTS t_user (
    id INT(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
    name VARCHAR(255) DEFAULT NULL COMMENT '用户名',
    money FLOAT DEFAULT NULL COMMENT '余额',
    PRIMARY KEY (id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';

    6.3.2 创建实体类

    在com.hg.pojo下创建User类,与数据库表映射:

    package com.hg.pojo;
    public class User {
    private Integer id;
    private String name;
    private Float money;
    // 无参构造
    public User() {}
    // 有参构造(方便测试)
    public User(String name, Float money) {
    this.name = name;
    this.money = money;
    }
    // getter/setter方法
    public Integer getId() { return id; }
    public void setId(Integer id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public Float getMoney() { return money; }
    public void setMoney(Float money) { this.money = money; }
    }

    6.3.3 创建 Mapper 接口与映射文件

    MyBatis 的 Mapper 接口无需实现类,由 Spring+MyBatis 自动生成代理对象。

    1、在com.hg.mapper下创建UserMapper接口:

    package com.hg.mapper;
    import com.hg.pojo.User;
    import org.apache.ibatis.annotations.Param;
    public interface UserMapper {
    // 添加用户
    void addUser(User user);
    // 扣钱
    void updateUserOfSub(@Param("source") String source, @Param("money") Float money);
    // 加钱
    void updateUserOfAdd(@Param("target") String target, @Param("money") Float money);
    }

    2、在同目录下创建UserMapper.xml映射文件,编写 SQL:

    <?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">
    <!– namespace必须与Mapper接口全类名一致 –>
    <mapper namespace="com.hg.mapper.UserMapper">
    <!– 添加用户 –>
    <insert id="addUser" parameterType="User">
    insert into t_user(name,money) values(#{name},#{money})
    </insert>
    <!– 扣钱 –>
    <update id="updateUserOfSub">
    update t_user set money=money-#{money} where name=#{source}
    </update>
    <!– 加钱 –>
    <update id="updateUserOfAdd">
    update t_user set money=money+#{money} where name=#{target}
    </update>
    </mapper>

    6.3.4 创建 Service 层

    在com.hg.service下创建UserService接口和实现类,通过@Autowired注入 Mapper 代理对象:

    // 接口
    package com.hg.service;
    import com.hg.pojo.User;
    public interface UserService {
    void addUser(User user);
    void updateUser(String source, String target, Float money);
    }

    // 实现类
    package com.hg.service.impl;
    import com.hg.mapper.UserMapper;
    import com.hg.pojo.User;
    import com.hg.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;

    @Service // 交给Spring管理
    public class UserServiceImpl implements UserService {
    // 自动注入Mapper代理对象(Spring已通过扫描器创建)
    @Autowired
    private UserMapper userMapper;

    @Override
    public void addUser(User user) {
    userMapper.addUser(user);
    }

    @Override
    public void updateUser(String source, String target, Float money) {
    // 扣钱
    userMapper.updateUserOfSub(source, money);
    // 加钱
    userMapper.updateUserOfAdd(target, money);
    }
    }

    6.4 测试整合效果

    使用 Spring 整合 JUnit 进行测试,无需手动创建 Spring 容器,在com.hg.test下创建ServiceTest:

    package com.hg.test;
    import com.hg.pojo.User;
    import com.hg.service.UserService;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

    // 整合Spring和JUnit
    @RunWith(SpringJUnit4ClassRunner.class)
    // 加载Spring配置文件
    @ContextConfiguration("classpath:applicationContext.xml")
    public class ServiceTest {
    // 自动注入Service
    @Autowired
    private UserService userService;

    // 测试添加用户
    @Test
    public void testAdd(){
    userService.addUser(new User("张三丰", 4000F));
    userService.addUser(new User("宋远桥", 2000F));
    }

    // 测试转账
    @Test
    public void testUpdate(){
    userService.updateUser("张三丰","宋远桥",1000F);
    }
    }

    执行测试方法,数据库表中会成功插入数据并完成转账,说明 Spring 与 MyBatis 整合成功!


    未完待续~~~

    赞(0)
    未经允许不得转载:171主机测评 » Spring 核心知识点全解析(续)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址