Spring5.0(第五版)

314 阅读23分钟

前言

不积跬步,无以至千里
不积小流,无以成江海

Spring框架简介

1.Spring是一个轻量级的开源的JavaEE框架。
2.Spring的目的是解决企业应用开发的复杂性。
3.Spring核心部分:IOC(控制反转)和AOP(面向切面编程)

Spring框架的特点

1.方便解耦,简化开发
将对象的创建和依赖关系的维护交给 Spring 管理。
2.AOP编程的支持
Spring提供面向切面编程,可以方便地实现对程序进行权限拦截和运行监控等功能
3.声明式事务的支持
只需要通过配置就可以完成对事务的管理,而无须手动编程。
4.方便集成各种优秀框架
Spring内部提供了对各种优秀框架(如 Struts2HibernateMyBatis 等)的直接支持。

Spring入门案例

1.下载Spring5https://spring.io/)

image.png

2.打开GitHub仓库Spring源码地址

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

3.IDEA创建一个Java工程

image.png

4.导入
spring-beans-5.2.6.RELEASE.jar
spring-context-5.2.6.RELEASE.jar
spring-core-5.2.6.RELEASE.jar
spring-expression-5.2.6.RELEASE.jar
commons-logging-1.1.1.jar(依赖的日志)

image.png

image.png

image.png

5.编写入门案例
5.1.创建User.class
public class User {

    private String userName;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    @Override
    public String toString() {
        return "User{" +
                "userName='" + userName + ''' +
                '}';
    }
}
5.2.创建spring的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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">

    <bean id="user" class="com.study.model.User"></bean>

</beans>
5.3.编写Main通过Spring上下文获取User对象
public class Main {

    public static void main(String[] args) {

        //1.加载Spring配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        //2.获取User
        User user = (User) applicationContext.getBean("user");
        user.setUserName("张三");
        System.out.println(user.toString());
    }
}
输出结果:
User{userName='张三'}
Process finished with exit code 0

image.png

IOC容器

1.什么是IOC
IOC全称:Inversion of Control控制反转。
IOC说明:对象的创建和对象之间的依赖关系交给容器控制,降低程序的耦合度。
2.IOC底层原理
三部分:1.XML解析 2.工厂模式 3.反射

通过解析XML配置文件,在工厂中通过反射创建对象,在通过工厂模式注入依赖来降低耦合。
3.IOC实现接口
IOC思想基于IOC容器完成,IOC容器就是对象工厂。
Spring提供IOC容器实现两种方式:(两个接口)
1.BeanFactory -->IOC容器基本实现,是Spring内置的接口并且是内部使用,一般不提供给开发者使用。
特点:加载配置文件的时候不会创建对象,获取(使用)对象的时候,才会创建对象。
 public static void main(String[] args) {
    BeanFactory beanFactory = new ClassPathXmlApplicationContext("nygjBean9.xml");
    User user = beanFactory.getBean("user", User.class);
    System.out.println(user.toString());
}

2.ApplicationContext -->是BeanFactory的子接口,提供了更多更强大的功能,提供给开发者使用。
特点:加载配置文件的时候就会创建在配置文件中的对象。
public static void main(String[] args) {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("nygjBean9.xml");
    User user = applicationContext.getBean("user", User.class);
    System.out.println(user.toString());
}

3.ApplicationContext接口实现类
  1.ClassPathXmlApplicationContext:加载类路径下的配置文件(也就是src路径下的配置文件)
  2.FileSystemXmlApplicationContext:加载绝对路径的配置文件(电脑上的盘符路径文件)

Bean管理XML方式

1.什么是Bean管理
Spring创建对象
Spring注入属性
<bean id="user" class="com.ytgj.model.User"></bean>
在Spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建。
(1)介绍Bean标签常用属性
id属性:表示唯一标识符
class属性:类全路径名
*:创建对象时候,默认使用对象的无参构造方法。
2)基于XML方式注入属性
set属性注入:使用property完成属性注入
<bean id="user" class="com.ytgj.model.User">
    <!-- name:类里面属性名 value:向属性注入的值-->
    <property name="name" value="张三"></property>
</bean>

构造注入:
<bean id="user" class="com.ytgj.model.User">
   <constructor-arg name="name" value="张三"/>
   <constructor-arg name="age" value="20" />
   <!--或者使用index方式-->
   <!--<constructor-arg index="0" value="张三"/>-->
   <!--<constructor-arg index="1" value="20" />-->
</bean>
3)P名称空间注入
使用p名称空间注入,可以简化XML配置方式
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p">
p名称空间底层也是使用set方式的注入
<bean id="user" class="com.ytgj.model.User" p:name="张三" p:age="21" ></bean>
4)注入NULL和特殊字符
注入null
<bean id="user" class="com.ytgj.model.User">
    <property name="name">
        <null></null>
    </property>
    <property name="age" value="20" />
</bean>
注入特殊字符
<bean id="user" class="com.ytgj.model.User">
    <property name="name">
        <value><![CDATA[<<张三01>>]]></value>
    </property>
    <property name="age" value="20" />
</bean>
5)注入外部Bean对象
1.dao
public interface UserDao {
    void eat();
}
public class UserDaoImpl implements UserDao {
    @Override
    public void eat() {
        System.out.println("eat---");
    }
}
2.service
public class UserService {
    private UserDao userDao;
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    public void eat(){
        userDao.eat();
    }
}
3.xml
<!-- 注入dao-->
<bean id="userDao" class="com.nygj.dao.impl.UserDaoImpl"></bean>
<!-- 注入service-->
<bean id="userService" class="com.nygj.service.UserService">
    <!-- 使用set方式注入userDao-->
    <property name="userDao" ref="userDao"/>
</bean>
6)注入内部Bean对象、级联赋值
public class Staff {
    private String name;
    private Dept dept;

    public void setName(String name) {
        this.name = name;
    }
    public void setDept(Dept dept) {
        this.dept = dept;
    }
    public Dept getDept() {
        return dept;
    }
}

<!-- 注入员工Bean-->
<bean id="staff" class="com.nygj.model.Staff">
    <property name="name" value="秦始皇"></property>
    <!-- 这种方式就是内部注入bean-->
    <property name="dept">
        <bean id="dept" class="com.nygj.model.Dept"></bean>
    </property>
    <!--dept.name 级联赋值。staff对象中需要存在dept的get方法 -->
    <property name="dept.name" value="科技部" />
</bean>
7)注入集合属性
public class Stu {
    private String[] courses;
    private List<String> lists;
    private Map<String,String> maps;
    private Set<String> sets;

    public void setCourses(String[] courses) {
        this.courses = courses;
    }
    public void setLists(List<String> lists) {
        this.lists = lists;
    }
    public void setMaps(Map<String, String> maps) {
        this.maps = maps;
    }
    public void setSets(Set<String> sets) {
        this.sets = sets;
    }
    @Override
    public String toString() {
        return "Stu{" +
                "courses=" + Arrays.toString(courses) +
                ", lists=" + lists +
                ", maps=" + maps +
                ", sets=" + sets +
                '}';
    }
}
<!-- xml -->
<bean id="stu" class="com.nygj.model.Stu">
    <!-- 数组-->
    <property name="courses">
        <array>
            <value>张三</value>
            <value>李四</value>
        </array>
    </property>
    <!-- list-->
    <property name="lists">
        <list>
            <value>张三</value>
            <value>李四</value>
        </list>
    </property>
    <!-- map-->
    <property name="maps">
        <map>
            <entry key="name" value="张三"></entry>
            <entry key="age" value="18"></entry>
        </map>
    </property>
    <!-- set-->
    <property name="sets">
        <set>
            <value>张三</value>
            <value>李四</value>
        </set>
    </property>
</bean>
8)注入集合对象属性
public class Stu2 {
    private List<User> userList;
    public void setUserList(List<User> userList) {
        this.userList = userList;
    }
    @Override
    public String toString() {
        return "Stu2{" +
                "userList=" + userList +
                '}';
    }
}
<!-- xml-->
<bean id="stu2" class="com.nygj.model.Stu2">
    <property name="userList">
        <list>
            <ref bean="user1" ></ref>
            <ref bean="user2" ></ref>
        </list>
    </property>
</bean>

<bean id="user1" class="com.nygj.model.User"></bean>
<bean id="user2" class="com.nygj.model.User"></bean>
9)使用命名空间抽取集合
public class Stu {
    private String[] courses;
    private List<String> lists;
    private Map<String,String> maps;
    private Set<String> sets;
    public void setCourses(String[] courses) {
        this.courses = courses;
    }
    public void setLists(List<String> lists) {
        this.lists = lists;
    }
    public void setMaps(Map<String, String> maps) {
        this.maps = maps;
    }
    public void setSets(Set<String> sets) {
        this.sets = sets;
    }
    @Override
    public String toString() {
        return "Stu{" +
                "courses=" + Arrays.toString(courses) +
                ", lists=" + lists +
                ", maps=" + maps +
                ", sets=" + sets +
                '}';
    }
}
<!-- xml-->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <!-- 1.定义util命名空间-->
    <!-- 2.使用util抽取集合属性-->
    <util:list id="nameList">
        <value>张三</value>
        <value>李四</value>
    </util:list>

    <util:map id="nameMap">
        <entry key="name" value="张三"></entry>
        <entry key="age" value="18"></entry>
    </util:map>
    
    <bean id="stu" class="com.nygj.model.Stu">
        <!-- 使用抽离的集合属性-->
        <property name="lists" ref="nameList"></property>
        <property name="maps" ref="nameMap"></property>
    </bean>
</beans>

FactoryBean

1.Spring中存在两种Bean对象,一种是普通Bean对象,另外一种是工程Bean对象(FactoryBean)。
普通bean:在配置文件中定义的bean类型就是返回类型。
工程bean:在配置文件中定义的bean类型可以和返回类型不一致。
1.创建类,让这个类作为工厂bean实现接口FactoryBean2.实现接口里面的方法,在实现的方法中定义返回的bean类型。
public class MyFactoryBean implements FactoryBean<User> {
    /**
     * 定义返回类对象
     * @return
     * @throws Exception
     */
    @Override
    public User getObject() throws Exception {
        return new User();
    }
    @Override
    public Class<?> getObjectType() {
        return null;
    }
    /**
     * 是否单例
     * @return
     */
    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }
}
<!-- xml -->
<bean id="myFactoryBean" class="com.nygj.model.MyFactoryBean"></bean>
<!-- main -->
public static void main(String[] args) {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("nygjBean5.xml");
    User user = applicationContext.getBean("myFactoryBean", User.class);
    System.out.println(user);
}

Bean作用域

Spring中,可以设置Bean是单例或多例对象。
在Spring中,默认情况下bean是单例的。
1.Spring配置文件中,bean标签里面有scope属性,可以设置对象是单例还是多例。
2.scope属性
singleton:默认值,表示是单例。.
prototype:表示是多例。
注意:scope属性存在多个值,这里只说明2个常用的。
3.singleton与prototype区别
singleton单例、prototype多例。
scope属性设置为singleton,在加载配置文件的时候,就会创建对象。
scope属性设置为prototype,不会在加载配置文件的时候创建对象,只有在获取对象(getBean)的时候,才创建对象。

Bean生命周期

1.通过构造器创建Bean实例(无参构造器)
2.Bean实例设置属性值(调用set方法)
3.Bean实例传递到Bean前置处理器方法--调用初始化之前方法postProcessBeforeInitialization()
4.调用Bean实例初始化的方法(需要进行配置)
5.Bean实例传递到Bean后置处理器方法--调用初始化之后方法postProcessAfterInitialization()
6.获取使用Bean实例(实例获取)
7.Bean实例销毁(需要进行配置)
<!-- Bean对象-->
public class Order {
    public Order(){
        System.out.println("步骤1 构造器创建对象");
        setOrderNo("001");
    }
    private String orderNo;
    public void setOrderNo(String orderNo) {
        this.orderNo = orderNo;
        System.out.println("步骤2 set方法设置属性");
    }
    public void init(){
        System.out.println("步骤4 初始化方法");
    }
    public void destruction(){
        System.out.println("步骤7 销毁方法");
    }
}
<!-- 处理器-->
public class OrderPost implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("步骤3 在初始化之前执行");
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("步骤5 在初始化之后执行");
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}

public static void main(String[] args) {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("nygjBean7.xml");
    Order order = applicationContext.getBean("order", Order.class);
    System.out.println("步骤6 获取实例对象"+order.toString());
    //手动关闭
    ((ClassPathXmlApplicationContext)applicationContext).close();
}
<!-- xml-->
<bean id="order" class="com.nygj.model.Order" init-method="init" destroy-method="destruction"></bean>
<!-- 后置处理器 会应用到配置文件中所有的Bean-->
<bean id="orderPost" class="com.nygj.handler.OrderPost"></bean>

步骤1 构造器创建对象
步骤2 set方法设置属性
步骤3 在初始化之前执行
步骤4 初始化方法
步骤5 在初始化之后执行
步骤6 获取实例对象com.nygj.model.Order@598067a5
步骤7 销毁方法

Process finished with exit code 0

自动装配

Spring的配置文件中,bean标签有一个属性autowire可以完成自动注入。
byName:根据属性名注入,注入值bean的id值和类属性名一样。
byType:根据属性类型注入
1.byName根据属性名称注入
public class Dept2 {
}

public class Emp2 {
    private Dept2 dept2;
    private String name;
    public void setDept2(Dept2 dept2) {
        this.dept2 = dept2;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Emp2{" +
                "dept2=" + dept2 +
                ", name='" + name + ''' +
                '}';
    }
}
<bean id="dept2" class="com.nygj.model.Dept2"></bean>
<!--byName根据名称注入 -->
<bean id="emp2" class="com.nygj.model.Emp2" autowire="byName"></bean>
2.byType:根据类型注入
<!--注意这里写的是dept3依然能够完成注入,因为是按照类型注入的。 -->
<bean id="dept3" class="com.nygj.model.Dept2"></bean>
<!--byName根据名称注入 -->
<bean id="emp2" class="com.nygj.model.Emp2" autowire="byType"></bean>

引入外部属性配置文件

public class User {
    private String name;
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + ''' +
                '}';
    }
}
<!-- xml-->
<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"
       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名称空间-->
    <!-- 引入外部文件-->
    <context:property-placeholder location="classpath:bean.properties"></context:property-placeholder>
    <bean id="user" class="com.nygj.model.User">
        <property name="name" value="${name}"></property>
    </bean>
</beans>

<!-- bean.properties外部文件-->
name=zhangsan

Bean管理注解方式

注解:注解是代码特殊标记。
格式:@注解名称(属性名称=属性值)
@Component:普通对象
@Service:业务层
@Controller:控制层
@Repository:dao层
四个注解的功能是一样,都可以用来创建注入bean实例。
1.引入依赖
spring-beans-5.2.6.RELEASE.jar
spring-context-5.2.6.RELEASE.jar
spring-core-5.2.6.RELEASE.jar
spring-expression-5.2.6.RELEASE.jar
spring-aop-5.2.6.RELEASE.jar
commons-logging-1.1.1.jar(依赖的日志)
2.开启组件扫描
<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"
       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命名空间-->
    
    <!-- 2.开启组件扫描-->
    <context:component-scan base-package="com.nygj"></context:component-scan>
</beans>
3.Java
@Component(value = "user")
//@Component 默认value就是类名,首字符小写驼峰
public class User {
}

public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("Bean1.xml");
    User user = context.getBean("user", User.class);
    System.out.println(user);
}
补充
<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"
       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">
    <!--
     use-default-filters="false"表示不使用默认filter
     context:include-filter 设置在base-package="com.nygj"下,只扫描指定的注解
     -->
    <context:component-scan base-package="com.nygj" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
    </context:component-scan>

    <!--
    use-default-filters="false"表示不使用默认filter
    context:exclude-filter 设置在base-package="com.nygj" 过滤排除指定的注解
    -->
    <context:component-scan base-package="com.nygj" use-default-filters="false">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    </context:component-scan>
</beans>

注解实现属性注入

@Resource与@Autowired

@Autowired与@Resource都可以用来装配bean. 都可以写在属性上,或写在setter方法上。 
@Autowired默认按类型装配(这个注解是属于spring的),默认情况下必须要求依赖对象必须存在,
如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果
我们想使用名称装配可以结合@Qualifier注解进行使用:
@Autowired() 
@Qualifier("baseDao")     
private BaseDao baseDao;    

@Resource(这个注解属于J2EE的 jdk1.6提供的),默认按照名称进行装配,名称可以通过name属性进行指定, 
如果没有指定name属性,当注解写在属性上时,默认取属性名进行按照名称查找,如果注解写在setter
方法上默认取方法属性名进行装配。 当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意
的是,如果name属性一旦指定,就只会按照名称进行装配。

@Resource(name="baseDao")     
private BaseDao baseDao; 

注解代替XML配置文件

1.创建配置类,代替XML配置
/**
 * Configuration 表示该类是一个配置类,等价于XML配置文件
 * @ComponentScan(basePackages = {"com.nygj"}) 代替<context:component-scan/>标签
 */
@Configuration
@ComponentScan(basePackages = {"com.nygj"})
public class SpringConfig {

}
2.Main
public class Main2 {

    public static void main(String[] args) {
        /**
         * new AnnotationConfigApplicationContext(SpringConfig.class)加载指定配置类
         */
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        User user = context.getBean("user", User.class);
        System.out.println(user);
    }
}

AOP

Aspect Oriented Programming
面向切面编程,使用代理方式来实现对程序中某些方法功能做增强处理。
SpringAop使用动态代理方式的,在运行期间通过代理方式向目标类织入增强代码。

应用场景:
事务管理、日志记录、方法耗时统计、安全检查等。


2.AspectJ
AspectJ是一个基于Java语言独立的AOP框架,不是Spring组成部分。
Spring2.0以后新增了对AspectJ切点表达式支持
@AspectJAspectJ 1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面



SpringAop是动态代理实现的:
1.需要代理的类实现了接口的话,采用JDK动态代理实现的,JDK提供了一个Proxy代理对象,创建代理对象,
然后将接口的方法交给InvocationHandler完成。

2.对类代理的话:通过CgLib动态代理实现的,采用ASM字节码生成代理类的。但是不能对声明为final的方法
进行代理,因为CgLib原理是动态生成被代理类的子类。
1.JDK代理
定义一个接口Hello,但是我们并不去编写实现类,而是直接通过JDK提供的一个
Proxy.newProxyInstance()创建了一个Hello接口对象。这种没有实现类但是在运行期动态创建了一个接口
对象的方式,我们称为动态代码。JDK提供的动态创建接口对象的方式,就叫动态代理。

public static Object newProxyInstance​(ClassLoader loader, 类<?>[] interfaces, InvocationHandler h)

参数说明:
`loader` - 用于定义代理类的类加载器
`interfaces` - 要实现的代理类的接口列表
`h` - 调度方法调用的调用处理程序

通过Proxy在内存中生成一个代理对象,通过代理对象代理需要被代理的类。
public class ProxyUserService {

    public static void main(String[] args) {

        //创建一个需要代理的实例
       final UserService userService = new UserServiceImpl();

       //通过Proxy  动态生成一个userService接口的实例
       UserService userServiceProxy = (UserService) Proxy.newProxyInstance(ProxyUserService.class.getClassLoader(),
               userService.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("~~~~~Hello~~~~~~");
                //在动态生成的userService实例方法中,调用需要被代理实例方法
                Object invoke = method.invoke(userService, args);
                System.out.println("~~~~~World~~~~~~");
                return invoke;
            }
        });
        userServiceProxy.add();
    }
}

AOP术语

1.连接点:可以被增强的方法称为连接点。
2.切入点:实际被增强的方法称为切入点。
3.通知:实际增强的逻辑部分称为通知。
4.切面:把通知应用到切入点的过程称为切面。

*通知五种类型:前置通知、后置通知、环绕通知、异常通知和最终通知。
切入点表达式语法:
execution([权限修饰符][返回类型][类全路径][方法名称]([参数列表]))
举例(1):execution(* com.spring.dao.UserDao.add(..)) 对com.spring.dao.UserDao类的add方法增强
举例(2):execution(* com.spring.dao.UserDao.*(..)) 对com.spring.dao.UserDao类的所有方法增强
举例(3):execution(* com.spring.dao.*.*(..)) 对com.spring.dao包所有类,所有方法增强

Spring整合AspectJ-注解方式

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.dwp</groupId>
    <artifactId>spring5_2025</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>spring5_2025</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
        <junit.version>5.9.2</junit.version>
    </properties>

    <dependencies>
        <!-- aop -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>6.1.4</version>
        </dependency>
        <!-- core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>6.1.4</version>
        </dependency>
        <!-- beans -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>6.1.4</version>
        </dependency>
        <!-- context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.1.4</version>
        </dependency>
        <!-- expression -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>6.1.4</version>
        </dependency>
        <!-- druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.9</version>
        </dependency>
        <!-- logging -->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.1</version>
        </dependency>
        <!-- aspects -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.10</version>
        </dependency>
    </dependencies>
</project>
<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
        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">

     <!-- 开启注解扫描-->
     <context:component-scan base-package="com.spring" />
     <!-- 开启Aspect生成代理对象-->
     <aop:aspectj-autoproxy />
</beans>
package com.spring.service;
import org.springframework.stereotype.Component;

@Component
public class UserServiceImpl {
    public void add(){
        System.out.println("add........");
    }
}
package com.spring.proxy;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class UserProxy {

    @Before(value = "execution(* com.spring.service.UserServiceImpl.add(..))")
    public void before(){
        System.out.println("前置通知.............");
    }

    @After(value = "execution(* com.spring.service.UserServiceImpl.add(..))")
    public void after(){
        System.out.println("后置通知.............");
    }

    @Around(value = "execution(* com.spring.service.UserServiceImpl.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        System.out.println("环绕前置通知.............");
        proceedingJoinPoint.proceed();
        System.out.println("环绕后置通知.............");
    }

    @AfterReturning(value = "execution(* com.spring.service.UserServiceImpl.add(..))")
    public void afterReturning(){
        System.out.println("后置返回通知.............");
    }

    @AfterThrowing(value = "execution(* com.spring.service.UserServiceImpl.add(..))")
    public void afterThrowing(){
        System.out.println("异常通知.............");
    }
}
package com.spring.main;

import com.spring.service.UserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AopMain {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        UserServiceImpl userServiceImpl = context.getBean("userServiceImpl", UserServiceImpl.class);
        userServiceImpl.add();
    }
}

环绕前置通知.............
前置通知.............
add........
后置返回通知.............
后置通知.............
环绕后置通知.............

Process finished with exit code 0
--相同切入点抽取
package com.spring.proxy;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class UserProxy {

    //相同切入点抽取
    @Pointcut(value = "execution(* com.spring.service.UserServiceImpl.add(..))")
    public void pointDemo(){}

    @Before(value = "pointDemo()")
    public void before(){
        System.out.println("前置通知.............");
    }

    @After(value = "pointDemo()")
    public void after(){
        System.out.println("后置通知.............");
    }

    @Around(value = "pointDemo()")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        System.out.println("环绕前置通知.............");
        proceedingJoinPoint.proceed();
        System.out.println("环绕后置通知.............");
    }

    @AfterReturning(value = "pointDemo()")
    public void afterReturning(){
        System.out.println("后置返回通知.............");
    }

    @AfterThrowing(value = "pointDemo()")
    public void afterThrowing(){
        System.out.println("异常通知.............");
    }
}
多个增强类对同一个方法进行增强,设置增强类优先级

@Order(0)
@Component
@Aspect
public class UserProxy2 {

    //相同切入点抽取
    @Pointcut(value = "execution(* com.spring.service.UserServiceImpl.add(..))")
    public void pointDemo(){}

    @Before(value = "pointDemo()")
    public void before(){
        System.out.println("UserProxy2前置通知.............");
    }

    @After(value = "pointDemo()")
    public void after(){
        System.out.println("UserProxy2后置通知.............");
    }

    @Around(value = "pointDemo()")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        System.out.println("UserProxy2环绕前置通知.............");
        proceedingJoinPoint.proceed();
        System.out.println("UserProxy2环绕后置通知.............");
    }

    @AfterReturning(value = "pointDemo()")
    public void afterReturning(){
        System.out.println("UserProxy2后置返回通知.............");
    }

    @AfterThrowing(value = "pointDemo()")
    public void afterThrowing(){
        System.out.println("UserProxy2异常通知.............");
    }
}
--------------------------------------------------------------
@Order(1)
@Component
@Aspect
public class UserProxy {

    //相同切入点抽取
    @Pointcut(value = "execution(* com.spring.service.UserServiceImpl.add(..))")
    public void pointDemo(){}

    @Before(value = "pointDemo()")
    public void before(){
        System.out.println("前置通知.............");
    }

    @After(value = "pointDemo()")
    public void after(){
        System.out.println("后置通知.............");
    }

    @Around(value = "pointDemo()")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        System.out.println("环绕前置通知.............");
        proceedingJoinPoint.proceed();
        System.out.println("环绕后置通知.............");
    }

    @AfterReturning(value = "pointDemo()")
    public void afterReturning(){
        System.out.println("后置返回通知.............");
    }

    @AfterThrowing(value = "pointDemo()")
    public void afterThrowing(){
        System.out.println("异常通知.............");
    }
}

UserProxy2环绕前置通知.............
UserProxy2前置通知.............
环绕前置通知.............
前置通知.............
add........
后置返回通知.............
后置通知.............
环绕后置通知.............
UserProxy2后置返回通知.............
UserProxy2后置通知.............
UserProxy2环绕后置通知.............

Process finished with exit code 0

Spring整合AspectJ-配置文件

1.创建增强类和被增强类
/**
 * 被增强类
 */
public class OrderServiceImpl {
    public void add(){
        System.out.println("order-add----------------");
    }
}

/**
 * 增强类
 */
public class OrderServiceProxy {
    public void before(){
        System.out.println("before-------------------");
    }
}
2.创建AOP配置文件
<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
        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">

      <!-- 创建对象-->
      <bean name="orderService" class="com.spring.service.OrderServiceImpl"></bean>
      <bean name="orderServiceProxy" class="com.spring.proxy.OrderServiceProxy"></bean>

      <!-- 配置aop增强-->
      <aop:config>
          <!-- 切入点-->
          <aop:pointcut id="point" expression="execution(* com.spring.service.OrderServiceImpl.add(..))"/>
          <!-- 配置切面-->
          <aop:aspect ref="orderServiceProxy">
                <aop:before method="before" pointcut-ref="point"/>
          </aop:aspect>
      </aop:config>
</beans>
3.测试
public class AopMain2 {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
        OrderServiceImpl orderServiceImpl = context.getBean("orderService", OrderServiceImpl.class);
        orderServiceImpl.add();
    }
}

before-------------------
order-add----------------

Process finished with exit code 0

JdbcTemplate

JdbcTemplate:Spring框架对JDBC进行封装,使用JdbcTemplate方便实现对数据库的操作。
1.pom文件
<!-- druid -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.9</version>
</dependency>
<!-- mysql -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.22</version>
</dependency>
<!-- tx -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>6.1.4</version>
</dependency>
<!-- jdbc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>6.1.4</version>
</dependency>
<!-- orm -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-orm</artifactId>
    <version>6.1.4</version>
</dependency>
2.配置文件 
<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
        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">
      
      <!-- 开启注解扫描-->
      <context:component-scan base-package="com.spring" />

      <!-- 数据库连接池-->
      <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
            <property name="url" value="jdbc:mysql://localhost:3306/spring_db?serverTimezone=UTC" />
            <property name="username" value="root" />
            <property name="password" value="**********" />
            <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
      </bean>

      <!-- 创建JdbcTemplate对象-->
      <bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <!-- 注入dataSource-->
            <property name="dataSource" ref="dataSource"></property>
      </bean>
</beans>
3.业务类编写
@Service
public class UserServiceJdbcImpl implements UserServiceJdbc {

    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Override
    public void add(User user) {
        //1.创建SQL语句
        String insertSql = "insert into user values(?,?)";
        //2.调用方法实现
        int update = jdbcTemplate.update(insertSql, user.getUserName(), user.getAge());
        System.out.println(update);
    }
}

public class JdbcMain {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("jdbc.xml");
        UserServiceJdbcImpl userServiceJdbcImpl = context.getBean("userServiceJdbcImpl", UserServiceJdbcImpl.class);

        User user = new User();
        user.setUserName("张三");
        user.setAge(28);
        userServiceJdbcImpl.add(user);
    }
}

image.png

事务概念

1.什么事务
事务是数据库操作的最基本单元,逻辑上一组操作,要么都成功,要么都失败,如果有一个失败所有操作都是失败。
2.事务四个特性
1.原子性(Atomicity):原子性是指事务是一个不可分割的最小工作单位,事务中的操作要么全部发生,要么都
不发生。如果事务中的某条SQL语句执行失败,那么与该事务相关的所有数据都将返回到事务执行前的状态。
2.一致性(Consistency):一致性是指在事务开始之前和事务结束以后,数据库的完整性没有被破坏。事务的执
行必须保持数据的完整性,确保数据库从一个一致的状态转移到另一个一致的状态。
3.隔离性(Isolation):隔离性是指一个事务的执行不能被其他事务干扰。多个并发事务之间相互隔离,确保每
个事务的操作不会互相干扰。隔离性可以防止脏读、不可重复读和幻读等问题。
4.持久性(Durability):持久性是指当事务正确完成后,它对数据库的改变是永久性的。即使系统发生故障,已
提交的事务对数据库的改变也不会丢失。
1.Spring事务
spring-tx.ja
r依赖包
PlatformTransactionManager:

平台事务管理器,spring要管理事务,必须使用事务管理器,进行事务配置时,必须配置事务管理器。
TransactionDefinition:
事务详情(事务定义、事务属性),spring用于确定事务具体详情。

TransactionStatus:
事务状态,spring用于记录当前事务运行状态。例如:是否有保存点,事务是否完成。
spring底层根据状态进行相应操作。

注意:Spring框架使用TransactionTemplate 需要配置事务管理器。而SpringBoot自动会注入事务
管理器。 如果你添加的是 spring-boot-starter-jdbc 依赖,框架会默认注入 
DataSourceTransactionManager 实例。如果你添加的是 spring-boot-starter-data-jpa 依赖,框架会
默认注入 JpaTransactionManager 实例。

Spring事务是基于底层数据库本身的事务处理机制实现的,在业务代码中进行事务管理。

2.Spring事务分类:
编程式事务(手动控制事务):
自己手动控制事务,就叫做编程式事务控制。使用TransactionTemplate或者直接使用
PlatformTransactionManager,对于编程式事务管理,
Spring推荐使用TransactionTemplate。比较灵活,但开发起来比较繁琐: 每次都要开启、提交、回滚。

声明式事务:
声明式事务管理建立在AOP之上,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个
事务,执行完目标方法之后根据执行的情况提交或者回滚。
具体实现:在配置文件中做相关的事务规则声明或者通过注解的方式实现。

优缺点:
声明式事务管理的粒度是方法级别,而编程式事务管理是可以到代码块的级别的。
声明式事务减少代码的冗余,编程式事务开发工作量大。
事务传播行为
Spring默认事务传播行为:PROPAGATION_REQUIRED

PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务,最常见的选择。
PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起, 两个事务之间没有关系。
PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
@Transactional注解参数配置
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.READ_UNCOMMITTED,timeout = -1,readOnly = false)
ioslation:事务隔离级别
(1)脏读:一个未提交事务读取到另外一个未提交事务的数据。
(2)不可重复读:一个未提交事务读取到另外一个提交事务修改的数据。
(3)幻读:一个未提交事务读取到另外一个事务提交的添加数据。 

脏读:事务A,B ,事务A读取了事务B更新还没提交的值,然后事务B回滚,这是事务A读取到值就是脏数据,无效
的数据。
不可重复读:事务A,B。事务A读取了一个字段,然后事务B更新了这个字段,事务A再重新读取的时候值不同了。
幻读:事务A,B.事务A读取了一个表中的所有数据,这个时候事务B在该表中插入了几条新的数据,事务A再次读取
的时候就会多出几行。

*--设置事务隔离级别,解决读问题。
读未提交(READ UNCOMMITTED):允许事务读取其他事务未提交的数据。脏读、不可重复度、幻读都会出现。
读已提交(READ COMMITED):只允许事务读取其他事务提交的变更。可以避免脏读。但不可重复度和幻读还会出现。
可重复读(REPEATABLE READ ):确保事务可以从一个字段中读取相同的值,在这个事务持续期间,禁止其他事务
对这个字段进行更新,可以避免脏读和不可重复读。但是幻读还会出现。
串行化(SERIALIZABLE):所有并发问题都可以解决,但性能十分低下。

timeout:超时时间
(1)事务需要在一定时间内进行提交,如果不提交进行回滚。
(2)默认值是-1,设置时间以秒为单位进行计算

readOnly:是否只读
(1)读:查询操作。写:添加修改删除操作。
(2)readOnly默认值false,表示可以查询,可以添加修改删除。
(3)设置readOnly值是true,设置成true之后,只能查询。

rollbackFor:回滚
(1)设置出现哪些异常进行事务回滚
noRollbackFor:不回滚
(1)设置出现哪些异常不进行事务回滚

Spring-XML方式配置事务

1.service业务类
@Service
public class TxOrderServiceImpl {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void txUpdateAge(){
        String up1 = "update user set age = age+? where id = ?";
        int update1 = jdbcTemplate.update(up1, -1, 1);
        System.out.println(update1);
        //异常
        int i=1/0;

        String up2= "update user set age = age+? where id = ?";
        int update2 = jdbcTemplate.update(up2, 1, 2);
        System.out.println(update2);
    }
}
2.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:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
        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">

      <!-- 开启注解扫描-->
      <context:component-scan base-package="com.spring" />

      <!-- 数据库连接池-->
      <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
            <property name="url" value="jdbc:mysql://localhost:3306/spring_db?serverTimezone=UTC" />
            <property name="username" value="root" />
            <property name="password" value="******" />
            <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
      </bean>

      <!-- 创建JdbcTemplate对象-->
      <bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <!-- 注入dataSource-->
            <property name="dataSource" ref="dataSource"></property>
      </bean>

      <!-- 1.创建事务管理器-->
      <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
          <!-- 注入数据源 -->
          <property name="dataSource" ref="dataSource"></property>
      </bean>
      <!-- 2.配置通知-->
      <tx:advice id="txOrder">
           <!-- 指定在哪些方法上添加事务-->
            <tx:attributes>
                  <tx:method name="txUpdateAge" propagation="REQUIRED"/>
            </tx:attributes>
      </tx:advice>

      <!-- 3.AOP应用事务-->
      <aop:config>
            <!-- 配置切入点-->
            <aop:pointcut id="tx" expression="execution(* com.spring.service.impl.TxOrderServiceImpl.txUpdateAge(..))"/>
            <!-- 配置切面-->
            <aop:advisor advice-ref="txOrder" pointcut-ref="tx"/>
      </aop:config>
</beans>
3.测试
public class JdbcMain {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("jdbc.xml");
        TxOrderServiceImpl txOrderServiceImpl = context.getBean("txOrderServiceImpl", TxOrderServiceImpl.class);
        txOrderServiceImpl.txUpdateAge();
    }
}

image.png

Spring-注解方式配置事务

1.service业务类
@Service
public class TxOrderServiceImpl {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Transactional //事务注解
    public void txUpdateAge(){
        String up1 = "update user set age = age+? where id = ?";
        int update1 = jdbcTemplate.update(up1, -1, 1);
        System.out.println(update1);
        //异常
        int i=1/0;

        String up2= "update user set age = age+? where id = ?";
        int update2 = jdbcTemplate.update(up2, 1, 2);
        System.out.println(update2);
    }
}
2.配置类
package com.spring.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

@Configuration //配置类
@ComponentScan(basePackages = "com.spring") //组件扫描
@EnableTransactionManagement //开启事务
public class TxConfig {

    //数据源
    @Bean
    public DruidDataSource getDruidDataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/spring_db?serverTimezone=UTC");
        dataSource.setUsername("root");
        dataSource.setPassword("*********");
        return dataSource;
    }

    //JdbcTemplate
    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource){
      JdbcTemplate jdbcTemplate = new JdbcTemplate();
      jdbcTemplate.setDataSource(dataSource);
      return jdbcTemplate;
    }

    //创建事务管理器
    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
       DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
       dataSourceTransactionManager.setDataSource(dataSource);
       return dataSourceTransactionManager;
    }
}
3.测试
public class JdbcMain2 {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(TxConfig.class);
        TxOrderServiceImpl txOrderServiceImpl = context.getBean("txOrderServiceImpl", TxOrderServiceImpl.class);
        txOrderServiceImpl.txUpdateAge();
    }
}

image.png

Spring整合log4j2日志框架

Spring5已经移除了Log4jConfigListener,官方建议使用Log4j2
1.整合Log4j2
<!-- log4j日志框架-->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.11.2</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.11.2</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.30</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.11.2</version>
    <scope>test</scope>
</dependency>
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别优先级OFF>FATAL>ERROR>WARN>INFO>DEBUG>TRACE>ALL -->
<!-- configuration后面的status用于设置log4j2自身内部的信息输出,可以不设置-->
<configuration status="INFO">
   <appenders>
       <!-- 输出日志信息到控制台-->
       <console name="Console" target="SYSTEM_OUT">
           <!-- 控制日志输出的格式-->
           <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss:SSS} [%t]%-5level %logger{36} - %msg%n"/>
       </console>
   </appenders>

   <!-- 定义了loggers并引入的appender,appender才会生效-->
   <!-- root:用于指定项目的根日志,如果没有单独指定Logger,则会使用root作为默认的日志输出-->
   <loggers>
       <root level="info">
          <appender-ref ref="Console"/>
       </root>
   </loggers>
</configuration>

SpringWebflux

Spring WebFluxSpring5.0版本引入的一个响应式Web框架,支持异步非阻塞的Web应用开发。Spring WebFlux
基于Reactor库,同时支持RxJava类库,构建响应式编程框架‌。

### 主要特性

1.异步非阻塞:Spring WebFlux基于响应式流,支持异步、非阻塞、事件驱动的服务,利用少量的线程处理大量的
并发请求‌。
2.Netty作为默认服务器:从Spring Boot2.x开始,默认采用Netty作为非阻塞I/O的Web服务器。它也可以在支持
Servlet 3.1规范的容器(如TomcatJetty)上运行‌。
3.响应式HTTP客户端:支持WebClient,用于异步非阻塞地发送HTTP请求‌。
4.响应式WebSocket:支持响应式的WebSocket服务开发‌。

### 架构和组件
Spring WebFlux的核心控制器是DispatcherHandler,类似于Spring MVC中的DispatcherServlet,负责将请求
分发给相应的处理器。DispatcherHandler通过查找Spring配置中的HandlerMappingHandlerAdapterHandlerResultHandler来处理请求‌。

### 使用场景
Spring WebFlux适用于IO密集型的应用场景,如微服务网关,可以显著提升对下游服务转发的吞吐量‌。此外,它
还适用于需要处理大量并发请求的应用,如实时数据分析、高并发Web应用等。