一、Bean 的创建
在Spring框架中,Bean是构成应用程序的基本组件,Spring容器负责管理这些Bean的生命周期和配置。Spring通过DI和IoC减少组件间的耦合度。
在Spring框架中,创建Bean的方式主要有两种:通过@Component
注解以及相关的派生注解(如@Service
, @Repository
, @Controller
),和通过@Bean
注解。这两种方式各有特点,适用于不同的场景。以下是对这两种方式的详细解释:
1. 使用@Component
及其派生注解
-
@Component
是一个通用的立体化注解,用于指示Spring框架该类是一个组件类,Spring应该为这个类创建Bean实例。 -
这个注解及其派生注解(
@Service
,@Repository
,@Controller
)都是通过类路径扫描自动检测来自动注册Bean的。这些注解通常用于自动扫描和自动装配Bean到Spring容器中。java@Component public class MyComponent { // 类体 } @Service public class MyService { // 服务层逻辑 } @Repository public class MyRepository { // 数据访问逻辑 } @Controller public class MyController { // Web层逻辑 }
特点
-
被注解的类将自动被Spring容器扫描和实例化。
-
适用于那些不需要太多自定义配置的Bean,主要通过类型安全的方式进行依赖注入。
2. 使用@Bean
注解
-
@Bean
注解通常用于配置类中,方法级别的注解,用于显式声明一个Bean,以及其生命周期的配置。 -
使用
@Bean
的方法返回一个对象的实例,Spring容器将注册返回的对象作为Beanjava@Configuration public class AppConfig { @Bean public MyBean myBean() { return new MyBean(); } } public class MyBean { public void doSomething() { // 业务逻辑 } }
-
提供了更多的灵活性,可以在方法中编写复杂的实例化逻辑。
-
适用于需要程序员精确控制Bean初始化方式和配置的场合,包括依赖的注入方式、作用域、生命周期回调等。
-
@Component
注解适用于自动扫描和装配,当你有大量需要注册的类且不需要特别指定太多配置时非常有用。 -
@Bean
注解提供了更精细的控制,特别适用于创建第三方库的对象,或者复杂的初始化逻辑,以及当你需要显式配置某些属性时。
二、Bean的使用和依赖注入(DI)
在Spring框架中,Bean的使用包括它们的创建、管理以及依赖注入(DI)。ApplicationContext
是Spring的高级容器,负责实例化、配置和组装Bean。
1. 依赖注入(DI)
依赖注入是一种允许对象定义它们依赖关系的设计模式,而无需知道如何构造它们。在Spring中,依赖注入主要有以下几种方式:
构造器注入:通过类的构造器注入依赖,这是推荐的注入方式,因为它可以保证所需依赖的不变性和必需性。
java
@Component
public class MyService {
private final MyRepository repository;
@Autowired
public MyService(MyRepository repository) {
this.repository = repository;
}
}
Setter注入:通过公开的setter方法注入依赖,适用于可选依赖。
java
@Component
public class MyService {
private MyRepository repository;
@Autowired
public void setRepository(MyRepository repository) {
this.repository = repository;
}
}
字段注入:直接在字段上注入依赖,虽然方便但是不推荐使用,因为它可能会导致依赖不明确和难以进行单元测试。
java
@Component
public class MyService {
@Autowired
private MyRepository repository;
}
2. ApplicationContext
ApplicationContext
是Bean工厂的扩展,提供了更多企业级功能,是Bean生命周期管理和高级配置的中心。Spring应用中的所有Bean都是由ApplicationContext管理的,它提供了以下功能:
- Bean实例化和配置 :容器使用Bean定义(如通过
@Component
或@Bean
注解提供的配置)来创建和配置所有的Bean。 - 自动装配 :
ApplicationContext
自动检测并配置Bean之间的依赖关系。 - 国际化:提供国际化的文本消息。
- 事件传播:支持事件和监听器,允许Bean接收数据变更或容器事件的通知。
- 不同层次的上下文:支持多个层次的上下文,允许继承配置。
以下是一个使用ApplicationContext
获取Bean实例的简单例子:
java
public class MyApp {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
MyService myService = ctx.getBean(MyService.class);
myService.performService();
}
}
三、Bean的作⽤域
作用域定义了Bean实例的创建、管理、和访问方式。下面是对每种作用域的详细介绍:
1. Singleton(单例作用域)
-
描述:这是Spring默认的作用域。在这种作用域中,Spring容器中每个Spring Bean定义只会创建一个实例。该实例在整个容器中是共享的,所有对该Bean请求都返回同一个实例。
-
用途 :适用于无状态的服务或单例模式需要的场合。
java@Component public class SingletonService { public void serviceMethod() { System.out.println("Singleton instance method called."); } }
2. Prototype(原型作用域)
-
描述:每次请求Bean时,Spring容器都会创建一个新的Bean实例,而不是返回现有的Bean。
-
用途 :适用于每个使用者都需要一个新实例的情况,例如,使用Bean来维护用户的状态。
java@Component @Scope("prototype") public class PrototypeBean { public void beanMethod() { System.out.println("Prototype instance " + this + " method called."); } }
3. Request(请求作用域)
-
描述:该Bean作用域限定在单个HTTP请求内。每个HTTP请求都会创建一个新的Bean实例,该实例仅在当前HTTP请求内有效。(依赖Web MVC)
-
用途 :适用于Web应用程序,每次HTTP请求需要独立处理的数据。
java@Component @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) public class RequestBean { public void printId() { System.out.println("Request bean instance " + System.identityHashCode(this)); } }
4. Session(会话作用域)
-
描述:该Bean作用域限定在HTTP会话内。每个HTTP会话创建一个Bean实例,该实例在整个会话期间共享。(依赖Web MVC)
-
用途 :适用于需要维护用户会话数据的情况,如用户登录信息。
java@Component @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS) public class SessionBean { public void printId() { System.out.println("Session bean instance " + System.identityHashCode(this)); } }
5. Application(应用作用域)
-
描述:Bean的作用域限定在ServletContext的生命周期内。这意味着Bean是全局共享的,与Singleton作用域类似,但是范围限定在整个Web应用上下文。(依赖Web MVC)
-
用途 :适用于需要跨多个Servlet共享数据的场合,如全局配置数据。
java@Component @Scope(value = WebApplicationContext.SCOPE_APPLICATION, proxyMode = ScopedProxyMode.TARGET_CLASS) public class ApplicationBean { public void printId() { System.out.println("Application scope bean instance " + System.identityHashCode(this)); } }
6. Websocket(WebSocket作用域)
-
描述:Bean的生命周期绑定到WebSocket会话的生命周期。每个WebSocket会话会创建一个Bean实例。(依赖Web MVC)
-
用途 :适用于基于WebSocket的通信应用,每个WebSocket会话需要单独管理的数据。
java@Component @Scope("websocket") public class WebSocketBean { public void handleMessage(String message) { System.out.println("Handling message in WebSocket session bean: " + message); } }
对于
request
,session
, 和websocket
作用域,你需要配置相应的Web环境和websocket配置,可能还需要使用proxyMode = ScopedProxyMode.TARGET_CLASS
以确保Bean是正确代理的,特别是在单例Bean中注入这些作用域的Bean时