您的位置:首页 > 财经 > 产业 > 女生学动漫设计好找工作吗_网站建设技术大全_怎么查询最新网站_适合发表个人文章的平台

女生学动漫设计好找工作吗_网站建设技术大全_怎么查询最新网站_适合发表个人文章的平台

2025/1/7 7:55:40 来源:https://blog.csdn.net/C18298182575/article/details/144916367  浏览:    关键词:女生学动漫设计好找工作吗_网站建设技术大全_怎么查询最新网站_适合发表个人文章的平台
女生学动漫设计好找工作吗_网站建设技术大全_怎么查询最新网站_适合发表个人文章的平台

在 Spring Boot 中,手动装配 Bean有哪些方式

my:@Bean /扫描 /Import /xml

在 Spring Boot 中,手动装配 Bean 是指显式地将类注册到 Spring 容器中,而不是依赖于自动扫描和注解。

以下是几种常见的手动装配方式:

1. 使用 @Bean 注解

通过在配置类中定义方法,将返回的对象注册为 Spring 容器中的 Bean。

实现步骤
  1. 创建一个配置类,使用 @Configuration 注解。
  2. 在方法上使用 @Bean 注解,将方法返回值注册为 Bean。
代码示例

@Configuration public class MyConfig { @Bean public MyService myService() { return new MyServiceImpl(); } }

  • 优点:简单直接,适用于单个或少量 Bean 的手动注册。
  • 场景:需要对 Bean 的实例化过程进行控制或设置属性。

2. 使用 @ComponentScan 配置自定义扫描路径

通过指定扫描路径或排除特定包/类来手动控制哪些类需要注册到 Spring 容器。

实现步骤
  1. 使用 @ComponentScan 注解配置扫描路径。
  2. 配合 @Component@Service 等注解自动注册。
代码示例

@SpringBootApplication @ComponentScan(basePackages = "com.example.custom") public class MyApplication { }

  • 优点:灵活性高,适合需要动态调整扫描路径的场景。
  • 场景:自定义模块化项目时,按需加载不同模块的 Bean。

3. 使用 @Import 注解

通过显式地导入其他配置类或直接导入组件类,将其注册到容器中。

实现步骤
  1. 在主配置类中使用 @Import 注解导入类。
  2. 导入的类可以是配置类或普通类。
代码示例

@Configuration @Import({MyService.class, MyRepository.class}) public class MyConfig { }

  • 优点:适用于需要显式注册多个相关类时。
  • 场景:模块化开发或导入外部库的配置。

4. 使用 SpringApplication 的 API

通过 Spring Boot 提供的 SpringApplication 类,手动注册 Bean。

实现步骤
  1. 定义自定义 Bean。
  2. 在启动类中手动注册 Bean。
代码示例

public static void main(String[] args) { SpringApplication app = new SpringApplication(MyApplication.class); app.addInitializers((applicationContext) -> { applicationContext.getBeanFactory().registerSingleton("myBean", new MyServiceImpl()); }); app.run(args); }

  • 优点:高度动态化,适合在运行时决定注册哪些 Bean。
  • 场景:需要动态调整注册逻辑。

5. 使用 BeanDefinitionRegistry

通过手动操作 BeanDefinitionRegistry,动态地向容器注册 Bean。

实现步骤
  1. 实现 BeanDefinitionRegistryPostProcessor 接口。
  2. 在 postProcessBeanDefinitionRegistry 方法中注册 Bean。
代码示例

@Component public class MyBeanRegistrar implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MyServiceImpl.class); registry.registerBeanDefinition("myService", builder.getBeanDefinition()); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { } }

  • 优点:极大的灵活性,可动态配置。
  • 场景:框架开发或需要动态注册 Bean 的复杂场景。

6. 使用 XML 配置

尽管在 Spring Boot 中 XML 配置已不常用,但仍可以通过引入 XML 文件来注册 Bean。

实现步骤
  1. 创建一个 XML 配置文件,定义 Bean。
  2. 在主配置类中通过 @ImportResource 导入 XML。
代码示例

<!-- applicationContext.xml --> <beans xmlns="http://www.springframework.org/schema/beans"> <bean id="myService" class="com.example.MyServiceImpl" /> </beans>

@Configuration @ImportResource("classpath:applicationContext.xml") public class MyConfig { }

  • 优点:适合遗留项目中整合 XML 配置。
  • 场景:迁移旧项目时保持兼容性。

Spring 提供了多种方式来管理事务

Spring 提供了多种方式来管理事务,主要包括以下几种方式:

1. 编程式事务管理(Programmatic Transaction Management)

  • 概述:通过编程的方式在代码中显式地控制事务的开始、提交和回滚。这种方式需要手动管理事务,通常通过 TransactionTemplate 或 PlatformTransactionManager 来实现。

  • 优点:可以灵活控制事务的细节,适用于一些复杂的事务处理逻辑。

  • 缺点:代码耦合度较高,事务的管理较为繁琐,容易出错,通常不推荐使用。

  • 示例

    @Autowired private PlatformTransactionManager transactionManager; public void someBusinessMethod() { DefaultTransactionDefinition def = new DefaultTransactionDefinition(); def.setName("SomeTransaction"); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); TransactionStatus status = transactionManager.getTransaction(def); try { // 执行数据库操作 transactionManager.commit(status); } catch (RuntimeException e) { transactionManager.rollback(status); throw e; } }

2. 声明式事务管理(Declarative Transaction Management)

  • 概述:通过配置和注解的方式来管理事务,不需要手动管理事务的开启和提交,Spring 会根据配置自动处理事务。常用的方式是使用 @Transactional 注解和 AOP(面向切面编程)来实现。

  • 优点:简洁且易于维护,事务管理与业务逻辑分离,减少了开发者的工作量。

  • 缺点:灵活性较差,不能处理一些非常复杂的事务需求。

  • 示例

    • 使用注解:

      @Transactional public void someBusinessMethod() { // 执行数据库操作,事务自动管理 }

    • 使用 XML 配置:

      <tx:annotation-driven /> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean>

3. 基于 AOP 的事务管理(AOP-based Transaction Management)

  • 概述:基于 AOP(面向切面编程),Spring 使用切面技术来拦截方法调用并在方法执行之前和之后处理事务。声明式事务管理就是通过 AOP 技术来实现的。
  • 优点:事务管理与业务代码分离,代码简洁,适合用于简单的事务管理。
  • 缺点:复杂的事务逻辑可能不适合使用 AOP,需要额外的配置和理解 AOP 的原理。
  • 示例:上面提到的 @Transactional 注解和 AOP 结合使用,Spring 会在运行时自动生成代理类来拦截方法并管理事务。

4. XML 配置的事务管理(XML-based Transaction Management)

  • 概述:通过在 XML 配置文件中配置事务管理器和事务的细节来管理事务。这种方式较为传统,通常与声明式事务管理结合使用。
  • 优点:可以集中配置事务管理,灵活性较高。
  • 缺点:配置较为繁琐,且不如注解方式简洁。
  • 示例

    <tx:annotation-driven /> <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean>

Spring 中的自动装配方式

Spring 中的自动装配是指 Spring 容器自动将需要的依赖注入到 Bean 中,从而减少了开发人员手动配置和创建 Bean 的工作。Spring 提供了多种自动装配的方式,主要通过注解和配置来实现。下面是几种常见的自动装配模式:

1. @Autowired 注解

@Autowired 是 Spring 用来自动装配 Bean 的最常用注解。它可以作用于构造器、字段、方法等,通过根据类型自动匹配依赖的 Bean。

1.1 按类型自动装配

Spring 默认会根据 Bean 的类型来匹配依赖的对象,如果有多个相同类型的 Bean,会抛出异常,除非指定了 @Qualifier 注解来指定具体的 Bean。

@Autowired private MyService myService; // 按类型自动装配

1.2 按构造函数自动装配

@Autowired 也可以加在构造函数上,Spring 会根据构造函数参数的类型自动装配 Bean。

@Autowired public MyController(MyService myService) { this.myService = myService; }

1.3 按方法自动装配

@Autowired 还可以应用于普通的 setter 方法上,Spring 会调用这些 setter 方法进行自动装配。

@Autowired public void setMyService(MyService myService) { this.myService = myService; }

2. @Qualifier 注解

当容器中有多个相同类型的 Bean 时,Spring 会根据类型进行自动装配,但如果有多个匹配的 Bean,就会抛出异常。在这种情况下,可以使用 @Qualifier 来指定要注入的具体 Bean。

@Autowired @Qualifier("myServiceImpl") private MyService myService;

这里 @Qualifier("myServiceImpl") 指定了具体的 Bean 名称,Spring 会根据该名称来选择注入的 Bean。

3. @Primary 注解

@Primary 是一个用于解决 Bean 冲突的注解。当多个相同类型的 Bean 存在时,可以通过 @Primary 注解标记一个 Bean,表示当有多个符合条件的 Bean 时,优先选择标记了 @Primary 的 Bean。

@Bean @Primary public MyService myPrimaryService() { return new MyServiceImpl(); }

使用 @Primary 标记的 Bean 会成为优先选择的 Bean,从而解决多个同类型 Bean 时的冲突问题。

4. @Value 注解

@Value 用于注入基本类型、配置文件中的值等。它允许将外部配置值(如 application.properties 文件中的属性)直接注入到 Bean 中。

@Value("${my.property.name}") private String propertyName;

@Value 也可以用于注入常量或表达式计算结果。

5. @Inject 注解

@Inject 是 JSR-330 标准的注解,功能与 @Autowired 类似。它由 Java EE 和 Spring 支持,但它没有 @Qualifier 和 @Primary 这样的配合注解,所以通常不如 @Autowired 强大。

@Inject private MyService myService;

6. 自动装配的启用方式

自动装配通常通过 @Configuration 和 @ComponentScan 配合使用,Spring 会自动扫描指定包中的所有类,并将它们作为 Bean 注入到容器中。

@Configuration @ComponentScan(basePackages = "com.example.service") public class AppConfig { // 配置类会自动扫描 com.example.service 包中的所有类并将其注入容器 }

7. @Component, @Service, @Repository, @Controller 等注解

这些注解是 Spring 提供的用于标记类的注解,它们都可以作为自动装配的候选类。它们的作用类似,区别在于它们的语义:

  • @Component:一般用来标记普通的 Bean。
  • @Service:通常用来标记服务层 Bean。
  • @Repository:通常用来标记 DAO 层 Bean。
  • @Controller:通常用来标记 Spring MVC 控制器类。

8. 自动装配的工作原理

Spring 容器使用反射机制和 BeanFactory 的 postProcessBeforeInitialization 等钩子方法来进行自动装配。在应用启动时,Spring 会通过以下过程来完成自动装配:

  1. 扫描 Bean 定义:通过 @ComponentScan 或配置类扫描容器中的所有 Bean 定义。
  2. 创建 Bean 实例:根据定义的 Bean 创建对应的实例。
  3. 自动装配依赖关系:通过 @Autowired 等注解将 Bean 的依赖关系自动注入,通常是通过类型匹配来实现的。

在 Spring 事务管理中,事务传播行为

在 Spring 事务管理中,事务传播行为(Transaction Propagation)定义了一个事务方法如何参与另一个事务的方法。

Spring 提供了以下几种常用的事务传播行为:

1. **PROPAGATION_REQUIRED**(默认传播行为)

  • 说明:如果当前存在事务,则加入该事务;如果当前没有事务,则新建一个事务。
  • 场景:这是最常见的传播行为,适用于大多数情况,尤其是当方法依赖于已有事务时。
  • 特性:如果没有事务,则会创建一个新的事务;如果已有事务,则加入该事务。

2. PROPAGATION_REQUIRES_NEW

  • 说明:无论当前是否存在事务,都会新建一个事务。如果当前存在事务,则会把当前事务挂起,直到新的事务完成后再恢复。
  • 场景:适用于需要独立事务的情况,确保事务不受外部事务的影响。常用于日志记录、支付等操作,独立处理时不想受父事务回滚的影响。
  • 特性:会挂起当前事务,启动新事务,执行完后再恢复原事务。

3. PROPAGATION_NESTED

  • 说明:如果当前存在事务,则在当前事务中创建一个嵌套事务;如果没有事务,则行为与 PROPAGATION_REQUIRED 相同。嵌套事务使用保存点(Savepoint),可以回滚到保存点。
  • 场景:适用于需要在一个大事务中处理子事务,并且希望子事务能够回滚但不影响整个事务的情况。
  • 特性:使用保存点管理事务,支持嵌套回滚。

4. PROPAGATION_SUPPORTS

  • 说明:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行。
  • 场景:适用于一些业务逻辑可能不需要事务控制,但如果已有事务时则需要加入该事务的场景。
  • 特性:当前事务存在时,加入该事务;否则以非事务方式执行。

5. PROPAGATION_NOT_SUPPORTED

  • 说明:如果当前存在事务,则将其挂起,并以非事务方式执行当前方法。
  • 场景:适用于需要执行一些不支持事务的操作时,如导出文件等,当前事务不应影响这些操作。
  • 特性:挂起当前事务,以非事务方式执行。

6. PROPAGATION_NEVER

  • 说明:当前方法不能在事务中执行。如果当前存在事务,则抛出异常。
  • 场景:适用于某些方法不能参与事务,且如果事务存在则抛出异常的情况。
  • 特性:如果当前已有事务,则抛出异常;如果没有事务,则正常执行。

7. PROPAGATION_MANDATORY

  • 说明:当前方法必须在一个事务中执行,如果当前没有事务,则抛出异常。
  • 场景:适用于必须要求事务存在的情况,确保方法执行时有一个事务。
  • 特性:如果当前没有事务,则抛出异常;如果当前有事务,则加入该事务。

事务传播行为对比:

传播行为当前有事务时当前没有事务时适用场景
PROPAGATION_REQUIRED加入当前事务新建事务默认行为,大多数场景
PROPAGATION_REQUIRES_NEW挂起当前事务,开启新事务新建事务需要独立事务的情况
PROPAGATION_NESTED在当前事务中创建嵌套事务新建事务嵌套事务,允许回滚
PROPAGATION_SUPPORTS加入当前事务非事务方式执行可能没有事务,加入已有事务
PROPAGATION_NOT_SUPPORTED挂起当前事务,非事务方式执行非事务方式执行不支持事务的操作
PROPAGATION_NEVER抛出异常非事务方式执行不允许事务
PROPAGATION_MANDATORY加入当前事务抛出异常必须在事务中执行

Spring 框架中常用的设计模式

my:单例 / 工厂 / AOP 代理 ,策略 /  restTemplate 模版

包装 inputStream / 观察者 ApplicationListner / 适配器 / 

Spring 框架是一个大型的应用程序开发框架,广泛应用了多种设计模式,以实现松耦合、高内聚和可扩展性。

以下是 Spring 框架中常用的一些设计模式:

1. 单例模式(Singleton Pattern)

  • 用途:保证整个 Spring 容器中只创建一个实例。
  • 应用:在 Spring 中,默认情况下,Bean 的作用域是单例的(除非显式指定为其他作用域)。这意味着每个 Bean 在容器中只会创建一个实例,所有请求都会共享这个实例。
  • 示例@Component@Service@Repository 等注解创建的 Bean 默认使用单例模式。

2. 工厂模式(Factory Pattern)

  • 用途:提供一个创建对象的接口,使得子类决定实例化哪个类。
  • 应用:Spring 使用工厂模式来实例化 Bean。Spring 的 BeanFactory 和 ApplicationContext 都是工厂类,用于从容器中创建和管理 Bean。
  • 示例BeanFactory 和 AnnotationConfigApplicationContext

3. 依赖注入(Dependency Injection,DI)

  • 用途:通过将对象的依赖关系注入到类中,从而解耦类与类之间的依赖。
  • 应用:Spring 的核心就是实现了依赖注入,提供了多种方式来注入依赖(构造函数注入、Setter 注入、字段注入)。
  • 示例@Autowired 注解、构造器注入。

4. 代理模式(Proxy Pattern)

  • 用途:为对象提供一个代理对象,控制对真实对象的访问。
  • 应用:Spring AOP 使用代理模式为对象提供切面功能。通过代理模式,Spring 在方法执行前后插入切面逻辑,而不需要修改原始对象代码。
  • 示例:Spring AOP 默认基于 JDK 动态代理或 CGLIB 代理。

5. 观察者模式(Observer Pattern)

  • 用途:一种对象状态改变时,依赖它的所有对象都会得到通知并自动更新。
  • 应用:Spring 的事件机制就是基于观察者模式实现的。ApplicationEventPublisher 用于发布事件,ApplicationListener 用于监听事件。
  • 示例@EventListener 注解用于监听 Spring 事件。

6. 模板方法模式(Template Method Pattern)

  • 用途:定义一个操作中的算法的骨架,将一些步骤的执行延迟到子类中。
  • 应用:Spring 提供了多种模板方法,如 JdbcTemplateJpaTemplate 等,用于简化常见的数据库操作。这些模板类会定义操作的基本步骤,而具体的操作逻辑由子类或调用者提供。
  • 示例JdbcTemplate 用于数据库操作。

7. 适配器模式(Adapter Pattern)

  • 用途:将一个类的接口转换成客户端所期待的另一个接口。
  • 应用:Spring 的 HandlerAdapter 适配器模式将 HTTP 请求与处理请求的 Controller 之间的接口进行了适配,以支持多种类型的处理器(如 SimpleControllerHandlerAdapter 和 AnnotationMethodHandlerAdapter)。
  • 示例HandlerAdapter 和 HandlerMapping

8. 责任链模式(Chain of Responsibility Pattern)

  • 用途:通过多个处理对象的链式传递来处理请求,每个处理对象可以决定是否处理请求,或者将请求传递给下一个处理对象。
  • 应用:Spring 中的 AOP 框架通过责任链模式来处理方法拦截。多个切面(Advice)可以按照顺序处理方法的执行。
  • 示例:多个 Advice 组成责任链,在方法执行前后执行额外的逻辑。

9. 构建者模式(Builder Pattern)

  • 用途:使用多个简单的对象一步一步构建成一个复杂的对象。
  • 应用:Spring 在配置 Bean 时,尤其是复杂的 Bean 配置,使用了构建者模式。@Configuration 注解的类往往是构建复杂 Bean 对象的地方。
  • 示例@Bean 方法中的 Bean 构建过程,ApplicationContext 的配置。

10. 策略模式(Strategy Pattern)

  • 用途:定义一系列算法,把它们一个个封装起来,并使它们可以相互替换。
  • 应用:Spring 通过策略模式使得不同的 Bean 配置方式能够相互替换,例如不同的 MessageSource 实现(ReloadableResourceBundleMessageSource 和 ResourceBundleMessageSource)都可以通过同一个接口 MessageSource 被使用。
  • 示例:Spring 配置中的不同 Bean 加载策略。

11. 迭代器模式(Iterator Pattern)

  • 用途:提供一种方法来顺序访问一个集合对象中的元素,而不暴露集合的内部表示。
  • 应用:Spring 的 Iterable 接口和 for-each 循环就是基于迭代器模式的。通过 Iterable,我们可以在不暴露底层数据结构的情况下遍历集合。
  • 示例:Spring 中的 Iterable,如 ApplicationContext 中的 BeanDefinition 集合。

12. 装饰器模式(Decorator Pattern)

  • 用途:动态地给一个对象添加一些额外的职责,而不影响其他对象。
  • 应用:Spring 使用装饰器模式来增强 Bean 的功能。例如,使用 ProxyFactoryBean 可以对 Bean 进行代理增强。
  • 示例:Spring AOP 中的代理机制,通过代理增强 Bean。

Spring MVC 的工作原理

Spring MVC 的工作原理可以分为以下几个主要步骤:

  1. 客户端发送请求

    • 客户端(通常是浏览器)通过 HTTP 向服务器发送请求。请求可以是 GET、POST、PUT、DELETE 等类型。
  2. 请求到达 DispatcherServlet

    • Spring MVC 的核心组件是 DispatcherServlet,它是前端控制器(Front Controller)。所有的 HTTP 请求都会首先到达 DispatcherServlet。这个 Servlet 是 Spring MVC 请求处理的起点,负责将请求分发到适当的处理器(Controller)。
  3. 请求映射到 Controller

    • DispatcherServlet 根据请求的 URL 和配置的映射关系(如注解 @RequestMapping 或 XML 配置)将请求分发到对应的 Controller。Controller 是处理请求的核心组件,它包含了业务逻辑。
  4. Controller 处理请求

    • Controller 从 HttpServletRequest 中提取请求信息(如参数、表单数据等),并调用相应的业务逻辑。处理完毕后,Controller 会返回一个 ModelAndView 对象,或直接返回数据。ModelAndView 包含了模型数据和视图名称。
  5. 视图解析

    • DispatcherServlet 接收到 ModelAndView 后,会根据返回的视图名称,结合配置的视图解析器(如 InternalResourceViewResolver),解析出对应的 视图(如 JSP 文件、Thymeleaf 模板等)。
  6. 渲染视图

    • 视图解析器将模型数据与视图结合,最终渲染成 HTML 页面返回给客户端。渲染过程中,模型数据可以通过模板引擎填充到视图模板中。
  7. 客户端接收响应

    • 客户端接收到服务器返回的响应数据后(通常是 HTML 页面或 JSON 格式的数据),并呈现给用户。

Spring MVC 的请求处理流程图

Client Request ---> DispatcherServlet ---> Handler Mapping ---> Controller ---> Model ---> View Resolver ---> View ---> Response to Client

详细工作流程

  1. 客户端请求

    • 用户通过浏览器向服务器发送请求,URL 可能包含路径、查询参数等。
  2. DispatcherServlet

    • DispatcherServlet 捕获所有的请求,它是请求处理的中央调度器。它会根据请求 URL 找到对应的处理方法。
  3. Handler Mapping

    • DispatcherServlet 会调用 HandlerMapping 组件来查找与请求 URL 匹配的 Controller 方法。Spring MVC 提供了多种类型的 HandlerMapping,如基于注解的 RequestMappingHandlerMapping,通过注解配置的 URL 映射到对应的 Controller 方法。
  4. Controller

    • DispatcherServlet 根据 HandlerMapping 返回的控制器,将请求交给 Controller 来处理。Controller 是业务逻辑处理的核心组件,负责解析请求数据,调用服务层进行逻辑处理,并返回模型数据。
  5. ModelAndView

    • Controller 处理完请求后,将业务数据和视图名称封装成 ModelAndView 对象,返回给 DispatcherServlet。其中 Model 包含了数据,View 是视图的逻辑名称。
  6. 视图解析

    • DispatcherServlet 调用 ViewResolver 组件根据返回的视图名称解析出具体的视图(如 JSP 页面或模板文件)。
  7. 视图渲染

    • 视图解析器加载视图并将模型数据渲染到视图中,最终生成 HTML 页面返回给客户端。
  8. 客户端响应

    • 客户端收到 HTML 响应后,浏览器将其渲染出来,展示给用户。

核心组件解析

  1. DispatcherServlet

    • Spring MVC 的核心控制器,所有的请求都由它来接收、分发、处理。
  2. HandlerMapping

    • 负责根据请求的 URL 查找对应的处理器(Controller)。常用的有 RequestMappingHandlerMapping(基于注解)和 BeanNameUrlHandlerMapping(基于 Bean 名称)。
  3. Controller

    • 处理请求的核心组件,包含业务逻辑。
  4. ViewResolver

    • 负责将逻辑视图名称解析为具体的视图实现(如 JSP 或 Thymeleaf 模板)。
  5. ModelAndView

    • 是一个对象,封装了模型数据和视图信息。模型包含了要展示给用户的数据,视图包含了如何展示这些数据的模板信息。

Spring 中的 Bean 生命周期

Spring 中的 Bean 生命周期是 Spring 容器管理 Bean 实例化、配置、初始化、销毁等过程的各个阶段。了解 Bean 的生命周期有助于更好地管理 Bean 的状态、资源的释放以及在应用中进行扩展。

Spring Bean 生命周期概述

Spring Bean 的生命周期包括以下几个主要阶段:

  1. 实例化:Spring 容器根据 Bean 定义(如 @Component 注解或 XML 配置)创建 Bean 实例。

  2. 属性填充:Spring 容器会根据配置文件或注解中的信息,将依赖注入到 Bean 的属性中。这一步通过反射完成,类似于构造方法注入或字段注入。

  3. 调用初始化方法

    • 如果 Bean 实现了 InitializingBean 接口,则 Spring 会调用 afterPropertiesSet() 方法。
    • 如果 Bean 配置了自定义的初始化方法(例如在 XML 配置文件中的 init-method 属性或通过注解 @PostConstruct),Spring 会在这个阶段调用这些方法。
  4. 使用 Bean:在这一步,Bean 被 Spring 容器完全初始化并可以使用。

  5. 销毁

    • 如果 Bean 实现了 DisposableBean 接口,则 Spring 会调用 destroy() 方法。
    • 如果 Bean 配置了自定义的销毁方法(例如在 XML 配置文件中的 destroy-method 属性或通过注解 @PreDestroy),Spring 会在容器关闭时调用这些方法。

Spring Bean 生命周期的详细步骤

  1. 实例化

    • Spring 根据配置的元数据(如 XML 文件、注解、Java 配置类等)创建 Bean 实例。实例化时,Spring 会使用无参构造方法或通过构造器注入的方式。
  2. 填充属性

    • Spring 使用反射机制,通过构造方法注入(constructor injection)或通过 setter 方法注入(setter injection)等方式,将依赖的属性或 Bean 填充到该 Bean 中。
  3. 调用初始化方法

    • InitializingBean 接口:如果 Bean 实现了 InitializingBean 接口,Spring 会调用其 afterPropertiesSet() 方法。
    • 自定义初始化方法:如果在配置文件(XML)中通过 init-method 属性指定了初始化方法,或者在 Java 配置中使用了 @Bean(initMethod = "methodName") 注解指定了初始化方法,Spring 会调用该方法。
    • @PostConstruct 注解:在 Java 配置类中,Bean 上可以标注 @PostConstruct 注解的方法,在所有属性填充完成后会被调用。
  4. 容器管理下的使用

    • 此时,Bean 已经完全初始化并可以由应用程序使用。容器管理的 Bean 可以通过 ApplicationContext.getBean() 方法获取,或者在需要的地方注入。
  5. 销毁 Bean

    • DisposableBean 接口:如果 Bean 实现了 DisposableBean 接口,Spring 容器在销毁该 Bean 时会调用其 destroy() 方法。
    • 自定义销毁方法:如果配置了自定义销毁方法(如在 XML 配置文件中通过 destroy-method 属性指定,或者在 Java 配置类中通过 @Bean(destroyMethod = "methodName") 注解指定),Spring 会在容器关闭时调用该方法。
    • @PreDestroy 注解:在 Java 配置类中,Bean 上可以标注 @PreDestroy 注解的方法,在销毁 Bean 时调用。

Spring Bean 生命周期的图示

+--------------------+ +------------------------+ | | | | | Bean实例化 | | 填充Bean属性 | | |------------> Bean依赖注入(setter、构造方法) | | | | | +--------------------+ +------------------------+ | | v +---------------------------+ +--------------------------+ | | | | | 调用初始化方法 |----> | 业务代码中的Bean使用 | | (InitializingBean、 | | 自定义的 init-method、 | | @PostConstruct) | | @PostConstruct等 | | | | | +---------------------------+ +--------------------------+ | | v +---------------------------+ +--------------------------+ | | | | | 销毁 Bean |<---- | 容器关闭,Bean销毁 | | (DisposableBean、 | | 自定义destroy-method、 | | @PreDestroy) | | @PreDestroy等 | | | | | +---------------------------+ +--------------------------+

常用的生命周期回调

  • 实现 InitializingBean 接口

    public class MyBean implements InitializingBean { @Override public void afterPropertiesSet() throws Exception { // 初始化逻辑 System.out.println("MyBean initialized."); } }

  • 实现 DisposableBean 接口

    public class MyBean implements DisposableBean { @Override public void destroy() throws Exception { // 销毁逻辑 System.out.println("MyBean destroyed."); } }

  • 使用 @PostConstruct 注解

    @Component public class MyBean { @PostConstruct public void init() { // 初始化逻辑 System.out.println("MyBean initialized with @PostConstruct."); } }

  • 使用 @PreDestroy 注解

    @Component public class MyBean { @PreDestroy public void cleanup() { // 销毁逻辑 System.out.println("MyBean destroyed with @PreDestroy."); } }

Bean 的作用域

在 Spring 框架中,Bean 的作用域 (Scope) 指定了 Spring 容器管理的 Bean 实例的生命周期和可见性。Spring 提供了多种作用域,用来控制 Bean 在容器中的创建、存在时间以及它们如何与其他 Bean 交互。常见的 Bean 作用域有以下几种:

1. 单例 (Singleton) — 默认作用域

  • 描述:在 Spring 容器启动时,只有一个 Bean 实例会被创建,并且该实例在整个 Spring 容器的生命周期内都会被复用。
  • 作用域范围:全局范围,Spring 容器中只有一个 Bean 实例。
  • 用法:这是默认的作用域。如果没有显式指定作用域,Spring 会创建一个单例 Bean。
  • 示例
     

    java

    @Component @Scope("singleton") // 默认值,可以省略 public class MySingletonBean { }

2. 原型 (Prototype)

  • 描述:每次从 Spring 容器请求 Bean 时,都会创建一个新的 Bean 实例。
  • 作用域范围:每次请求都会返回一个新的 Bean 实例。
  • 用法:适用于需要每次都创建新的 Bean 实例的场景,比如状态不同的对象。
  • 示例
     

    java

    @Component @Scope("prototype") public class MyPrototypeBean { }

3. 请求 (Request)

  • 描述:每个 HTTP 请求都会创建一个新的 Bean 实例。这个作用域仅在基于 web 的 Spring 应用中有效(如 Spring MVC)。
  • 作用域范围:每个 HTTP 请求会有一个独立的 Bean 实例。
  • 用法:适用于与每个 HTTP 请求相关的 Bean,例如保存当前请求的状态或用户信息。
  • 示例
     

    java

    @Component @Scope("request") public class MyRequestBean { }

4. 会话 (Session)

  • 描述:每个 HTTP 会话(HTTP session)会创建一个新的 Bean 实例。这个作用域仅在基于 web 的 Spring 应用中有效。
  • 作用域范围:每个 HTTP 会话对应一个 Bean 实例。
  • 用法:适用于需要在用户的会话中维持状态的 Bean,如保存用户信息、购物车等。
  • 示例
     

    java

    @Component @Scope("session") public class MySessionBean { }

5. 应用 (Application)

  • 描述:在整个 Servlet 容器的生命周期内,只有一个 Bean 实例存在。这种作用域是基于 Web 应用的,每个应用中会有一个 Bean 实例。
  • 作用域范围:在整个应用范围内共享一个 Bean 实例。
  • 用法:适用于应用范围的共享 Bean,如某些跨会话的服务对象。
  • 示例
     

    java

    @Component @Scope("application") public class MyApplicationBean { }

6. 全局会话 (Global Session)

  • 描述:此作用域类似于 session,但是它仅在基于 portlet 的 web 应用中有效。全局会话作用域是针对多 portlet 应用的。
  • 作用域范围:在全局会话范围内共享一个 Bean 实例。
  • 用法:适用于多端口的 web 应用场景,通常在 portlet 环境下使用。
  • 示例
     

    java

    @Component @Scope("globalSession") public class MyGlobalSessionBean { }

7. 自定义作用域

  • 描述:除了 Spring 提供的标准作用域,还可以自定义作用域。通过实现 Scope 接口,可以定义一个自定义的作用域。
  • 用法:当默认的作用域不适合你的需求时,可以定义自己的作用域逻辑。
  • 示例
     

    java

    @Component @Scope("customScope") public class MyCustomScopeBean { }

作用域的总结:

作用域描述生命周期使用场景
Singleton单例作用域,容器中只有一个实例整个应用生命周期适用于全局共享的数据、服务、工具类等
Prototype每次请求创建一个新的 Bean 实例每次请求一个新的实例适用于每次请求需要不同实例的场景
Request每个 HTTP 请求创建一个新的 Bean 实例每个 HTTP 请求周期内创建实例适用于每个请求相关的状态或数据
Session每个 HTTP 会话创建一个新的 Bean 实例每个 HTTP 会话生命周期内创建实例适用于保存会话状态的对象,如用户信息
Application在整个 Servlet 容器中只有一个实例整个 Web 应用生命周期适用于应用级别的共享对象
GlobalSession在多 portlet 环境中每个全局会话有一个实例整个全局会话生命周期适用于多 portlet 的场景

作用域的使用:

  1. Spring XML 配置
     

    xml

    <bean id="myBean" class="com.example.MyBean" scope="prototype"/>
  2. 注解配置
     

    java

    @Component @Scope("singleton") public class MyBean { }

小结:

  • Singleton 和 Prototype 是最常用的作用域,前者适合全局共享,后者适合每次创建新的实例。
  • RequestSessionApplication 等作用域适用于 Web 环境,用于处理 HTTP 请求、会话等特定场景。

IOC

IOC(Inversion of Control,控制反转)是 Spring 框架的核心思想之一,用来解耦对象之间的依赖关系。通过 IOC,Spring 容器管理对象的创建、初始化、生命周期和依赖注入,开发者只需关注业务逻辑,无需手动管理对象间的依赖关系。


IOC 的核心概念

1. 控制反转
  • 传统方式:对象自己控制其依赖对象的创建和生命周期。
  • IOC 方式:将对象的控制权交给 Spring 容器,由容器负责依赖对象的创建和管理。
2. 依赖注入

IOC 的实现方式主要是 依赖注入(Dependency Injection, DI)。通过 DI,容器将对象所依赖的其他对象注入进来。常见注入方式:

  • 构造器注入:通过构造器传递依赖对象。
  • Setter 方法注入:通过 Setter 方法传递依赖对象。
  • 字段注入:直接在字段上使用注解注入依赖对象。

IOC 的工作原理

  1. 配置 Bean

    • 开发者通过 XML 文件、注解(如 @Component)或 Java 配置类(如 @Configuration)声明需要由 Spring 管理的 Bean。
  2. 创建容器

    • Spring 容器读取配置文件/类,扫描组件,加载并解析 Bean 的定义。
  3. 依赖解析

    • Spring 根据 Bean 的依赖关系(通过构造器参数、@Autowired 等)解析依赖。
  4. Bean 实例化

    • 容器通过反射创建 Bean 实例。
  5. 依赖注入

    • 容器将依赖对象注入到目标 Bean 中。
  6. 管理生命周期

    • Spring 通过 BeanPostProcessor 等机制,对 Bean 进行初始化、销毁等生命周期管理。

IOC 的优点

  1. 解耦

    • 对象之间通过接口和配置进行依赖关系管理,而不是直接创建对象,降低了模块之间的耦合。
  2. 易于扩展

    • 通过配置文件或注解,可以动态更换依赖对象而无需修改代码。
  3. 统一管理

    • 所有对象由容器管理,便于集中控制对象的生命周期和依赖关系。
  4. 方便测试

    • 可以通过容器注入 mock 对象,便于单元测试。
  5. 增强功能

    • IOC 容器支持 AOP、事务管理等功能,能轻松为 Bean 添加额外的逻辑。

IOC 的实现示例

1. 基于 XML 的 IOC 配置

<beans> <bean id="userService" class="com.example.UserService"> <property name="userRepository" ref="userRepository" /> </bean> <bean id="userRepository" class="com.example.UserRepository" /> </beans>

2. 基于注解的 IOC 配置

@Component public class UserService { @Autowired private UserRepository userRepository; } @Component public class UserRepository { }

3. 基于 Java 配置的 IOC

@Configuration public class AppConfig { @Bean public UserService userService() { return new UserService(userRepository()); } @Bean public UserRepository userRepository() { return new UserRepository(); } }


IOC 和 DI 的区别

  • IOC 是一种思想,强调控制权的反转。
  • DI 是实现 IOC 的一种具体方式,通过注入的方式解决对象依赖问题。

循环依赖

Spring 框架在创建和管理 Bean 的过程中可能会遇到循环依赖问题,即两个或多个 Bean 之间存在互相引用。Spring 通过多种方式解决循环依赖,具体方法取决于 Bean 的作用域和依赖注入的类型。


1. 单例作用域(Singleton Scope)下的循环依赖

原理
  • Spring 使用 三级缓存 机制解决单例 Bean 的循环依赖:
    1. Singleton Objects Cache(一级缓存):
      • 已经完全初始化并可供直接使用的单例 Bean。
    2. Early Singleton Objects(二级缓存):
      • 提前暴露的原始单例对象,用于解决循环依赖。
    3. Singleton Factories(三级缓存):
      • 存放 Bean 的 ObjectFactory,用于创建早期 Bean 实例。
过程
  • 当 A 和 B 存在循环依赖时:
    1. Bean A 初始化开始:A 的实例创建后,放入三级缓存中(通过 ObjectFactory 提供 Bean 的早期引用)。
    2. Bean B 初始化开始:B 需要 A 的引用,Spring 从三级缓存中获取 A 的早期引用,完成 B 的初始化。
    3. 完成 Bean A 初始化:A 获取 B 的引用并完成初始化。
    4. 缓存升级:将 A 和 B 从三级缓存移到一级缓存,完成依赖注入。
注意
  • 循环依赖可以通过 Setter 注入 或 字段注入 解决。
  • 如果使用 构造器注入,则无法解决循环依赖(见下文)。

2. Prototype 作用域下的循环依赖

  • Spring 无法自动解决 Prototype Scope 的循环依赖。
  • 原因:Prototype Bean 不会被缓存,Spring 每次需要都会创建新实例,无法提前暴露 Bean 的早期引用。
  • 解决方法
    • 重构代码:避免循环依赖。
    • 使用 Setter 注入:手动延迟依赖的注入。

3. 构造器注入的循环依赖

问题
  • 如果两个或多个 Bean 使用 构造器注入 且相互依赖,Spring 无法解决循环依赖。
  • 原因:构造器注入需要在 Bean 完全初始化之前完成依赖注入,而此时对象尚未生成,无法暴露早期引用。
解决方法
  • 重构设计:消除循环依赖,例如将其中一个依赖转换为 Setter 注入。
  • 使用 @Lazy 注解
    • 延迟加载某些 Bean,避免在构造器中直接触发依赖注入。

4. @DependsOn 注解的使用

  • Spring 提供 @DependsOn 注解,用于显式指定 Bean 的初始化顺序。
  • 适用于某些特定场景,但不建议依赖此方式解决循环依赖。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com