【Spring】01-Spring及IOC,AOP

cover-01

[toc]

Spring

Spring使Java编程对每个人来说都更快、更容易、更安全。Spring对速度、简单性和生产力的关注使其成为世界上最受欢迎的Java框架。目的是为了解决企业级应用开发的业务逻辑层和其他各层的耦合问题。

  1. Spring核心的八个模块
    • Spring Core:基础,提供 IOC 和 DI 能力,可以说 Spring 其他所有的功能都依赖于该类库。
    • Spring Aspects:该模块为集成 AspectJ 提供支持。
    • Spring AOP:提供面向方面的编程实现。
    • Spring JDBC:Java 数据库连接。
    • Spring JMS:Java 消息服务。
    • Spring ORM:用于支持 Hibernate、Mybatis 等 ORM 工具。
    • Spring Web:为创建 Web 应用程序提供支持。
    • Spring Test:提供了对 JUnit 和 TestNG 测试框架的支持。
  2. Spring中使用的设计模式
    • 工厂模式:包括简单工厂和工厂方法,如通过 BeanFactory 或 ApplicationContext 创建 Bean 对象。
    • 单例模式:Spring 中的 Bean 对象默认就是单例模式。
    • 代理模式:Spring AOP 就是基于代理实现的,包括 JDK 动态代理和 CGlib 技术。
    • 模板方法模式:Spring 中 jdbcTemplate 等以 Template 结尾对数据库操作的类就使用到模板模式。
    • 观察者模式:Spring 事件驱动模型就是观察者模式很经典的应用。
    • 适配器模式:Spring MVC 中,DispatcherServlet 根据请求解析到对应的Handler(也就是我们常说的 Controller)后,开始由 HandlerAdapter 适配器处理。
    • 装饰者模式:使用 DataSource 在不改动代码情况下切换数据源。
    • 策略模式:Spring 对资源的访问,如 Resource 接口。

IOC

IOC(Inversion of Control)即控制反转

IOC底层原理

IOC的思想基于IOC容器完成,IOC容器的底层就是对象工厂。

IOC提供的接口

Spring提供IOC容器实现的两种方式:

  1. BeanFactory:IOC容器的基本实现,是Spring内部使用的接口。不提供开发人员使用。
    1. 加载配置文件的时候不会创建对象,在获取(使用)对象时才创建对象。
  2. ApplicationContext:BeanFactory的子接口,提供更多更强大的功能。一般由开发人员使用。
    1. 加载配置文件的时候,就对会配置文件中的对象进行创建。
    2. 继承 MessageSource,支持国际化。
    3. 统一的资源文件访问方式。
    4. 提供在监听器中注册 Bean 的事件。
    5. 支持同时加载多个配置文件。
    6. 载入多个(有继承关系)上下文,使得每一个上下文都专注于一个特定的层次,如应用的 Web 层。

ApplicationContext接口的实现类

  1. ClassPathApplicationContext:src下的相对路径
  2. FileSystemXmlApplicationContext:绝对路径
  3. WebXmlApplicationContext:该容器会在一个 Web 应用程序的范围内加载在 XML 文件中已被定义的 Bean

BeanFactory接口的实现类

  1. ConfigurableApplicationContext

IOC操作Bean管理

Bean管理的两步操作

  1. IOC创建对象
  2. IOC注入属性

Bean管理操作的两种方式

  1. 基于xml配置文件的方式
  2. 基于注解的方式

xml方式创建对象

项目结构

img-03

  1. User

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    package com.spring5.zsq.entity;

    /**
    * @author zsq
    * @create 2023-02-25-14:29:38
    */
    public class User {

    private String name;
    private Integer age;
    private Integer gender;

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    public Integer getAge() {
    return age;
    }

    public void setAge(Integer age) {
    this.age = age;
    }

    public Integer getGender() {
    return gender;
    }

    public void setGender(Integer gender) {
    this.gender = gender;
    }

    @Override
    public String toString() {
    return "User{" +
    "name='" + name + '\'' +
    ", age=" + age +
    ", gender=" + gender +
    '}';
    }

    }
  2. beanUser.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <?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对象 -->
    <bean id="user" class="com.spring5.zsq.entity.User">
    </bean>

    </beans>
  3. Spring5Test.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    package com.spring5.zsq.test;

    import com.spring5.zsq.entity.User;
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;

    /**
    * @author zsq
    * @create 2023-02-25-14:31:16
    */
    public class Spring5Test {

    @Test
    public void test() {
    // 1. 加载spring配置文件
    ApplicationContext context = new ClassPathXmlApplicationContext("beanUser.xml");

    // 2. 获取配置创建的对象
    User user = context.getBean("user", User.class);
    System.out.println(user);
    }

    }
  4. Spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建。

  5. 在bean标签里有很多属性:

    1. id:唯一标识
    2. class:类全路径IOC操作Bean管理(基于注解)
    3. name:不常使用
  6. 创建对象时,默认执行无参构造方法。若对象没有无参构造会报错

基于xml方式注入属性

  1. DI:依赖注入,就是注入属性
通过set方法注入属性
  1. userBean.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <?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对象 -->
    <bean id="user" class="com.spring5.zsq.entity.User">
    <property name="name" value="张三"/>
    <property name="age" value="33"/>
    <property name="gender" value="1"/>
    </bean>

    </beans>
  2. 运行结果

    img-04

通过构造方法注入属性
  1. User.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    package com.spring5.zsq.entity;

    /**
    * @author zsq
    * @create 2023-02-25-14:29:38
    */
    public class User {

    public User(String name, Integer age, Integer gender) {
    this.name = name;
    this.age = age;
    this.gender = gender;
    }

    private String name;
    private Integer age;
    private Integer gender;

    @Override
    public String toString() {
    return "User{" +
    "name='" + name + '\'' +
    ", age=" + age +
    ", gender=" + gender +
    '}';
    }

    }
  2. userBean.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <?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对象 -->
    <bean id="user" class="com.spring5.zsq.entity.User">
    <!-- 构造器参数 -->
    <constructor-arg name="name" value="李四"/>
    <constructor-arg name="age" value="44"/>
    <constructor-arg name="gender" value="2"/>
    <!-- 通过构造器参数位置注入属性 -->
    <!--<constructor-arg index="0" value="name"/>-->
    </bean>

    </beans>
  3. 运行结果

    img-05

p命名空间注入属性

Bean

Bean的作用域

Bean是否是线程安全的

Bean的生命周期

img-06

AOP

AOP(Aspect Oriented Programming),面向切面编程

AOP的实现原理

  1. JDK 动态代理:利用拦截器加反射机制生成一个实现代理接口的匿名类
  2. CGlib:利用 ASM 开源包修改字节码生成子类,且不支持 Final 修饰的方法

事务

事务的开启方式

  1. 编程式事务:将事务的管理代码嵌入到业务代码中,来控制事务的提交和回滚。使用PlatfromTransactionManagerTransactionTemplate 来管理事务。

  2. 声明式事务:将事务管理代码从业务方法中抽离了出来,以声明式的方式来实现事务管理。使用@Transactional来管理事务

    缺点:声明式事务管理的粒度是方法级别的,而编程式事务可以精确到代码块级别

Transaction的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {

// 该事务对应的事务管理器
@AliasFor("transactionManager")
String value() default "";

//
@AliasFor("value")
String transactionManager() default "";

//
String[] label() default {};

// 事务传播方式
Propagation propagation() default Propagation.REQUIRED;

// 事务隔离级别
Isolation isolation() default Isolation.DEFAULT;

// 超时时间
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;

//
String timeoutString() default "";

// 读/写 与 只读 事务
boolean readOnly() default false;

// 需要回滚的异常
Class<? extends Throwable>[] rollbackFor() default {};

// 需要回滚的异常类名
String[] rollbackForClassName() default {};

// 不需要回滚的异常
Class<? extends Throwable>[] noRollbackFor() default {};

// 不需要回滚的异常类名
String[] noRollbackForClassName() default {};


}

propagetion 事务的传播行为

TransactionDefinition一共定义了7种事务的传播行为。

常用的是PROPAGATION_REQUIRED, PROPAGATION_REQUIRES_NEW 两种

PROPAGATION.REQUIRED

默认的事务传播行为。如果当前事务不存在,就创建一个新的事务。

  1. 当外部方法没有开启事务,而当前方法使用PROPAGATION_REQUIRED修饰的话,内部方法会开启自己的事务。
  2. 如果外部方法也开启事务,并且外部方法和当前方法都是用PROPAGATION_REQUIRED修饰的话,内外部方法同属于一个事务,只要一个方法回滚,整个事物都需要回滚。
PROPAGATION.REQUIRES_NEW

需要创建一个新的事务,如果当前存在事务,则把当前事务挂起,重新创建一个新的事务。

当类A中的a方法使用的是默认的PROPAGATION_REQUIRED,a方法的子方法b使用的是PROPAGATION_REQUIRED_NEW。若a方法抛出异常,b方法不受影响;若b方法抛出异常,a方法会受到影响。

PROPAGATION.NESTED(嵌套事务)
PROPAGATION.SUPPORTS

支持事务,如果没有事务,则以非事务的方式运行

PROPAGATION.NOT_SUPPORTS

不支持事务,以非事务的方式运行,如果存在事务,则挂起

PROPAGATION.NEVER

不支持事务,如果存在事务,则抛出异常

PROPAGATION.MANDATORY

isolation 事务的隔离级别

timeout 事务的过期时间

readOnly 事务是否只读

-------------本文结束感谢您的阅读-------------