控制反转实现方式
XML方式
语法
<bean id="对象名称" class="全限定类名">
创建方式
方式一:直接创建对象
<bean class="com.xszx.service.impl.UserServiceImpl02" id="userService" />
方式二:spring 管理静态工厂-使用静态工厂的方法创建对象 (了解)
/**
* 模拟一个静态工厂,创建业务层实现类
*/
public class StaticFactory {
public static IAccountService createAccountService(){
return new AccountServiceImpl();
}
}
<!-- 此种方式是:
使用 StaticFactory 类中的静态方法 createAccountService 创建对象,并存入 spring 容器
id 属性:指定 bean 的 id,用于从容器中获取
class 属性:指定静态工厂的全限定类名
factory-method 属性:指定生产对象的静态方法
-->
<bean id="accountService"
class="com.xszx.factory.StaticFactory"
factory-method="createAccountService"></bean>
方式三:spring 管理实例工厂-使用实例工厂的方法创建对象 (了解)
/**
* 模拟一个实例工厂,创建业务层实现类
* 此工厂创建对象,必须现有工厂实例对象,再调用方法
*/
public class InstanceFactory {
public IAccountService createAccountService(){
return new AccountServiceImpl();
}
}
<!-- 此种方式是:
先把工厂的创建交给 spring 来管理。
然后在使用工厂的 bean 来调用里面的方法
factory-bean 属性:用于指定实例工厂 bean 的 id。
factory-method 属性:用于指定实例工厂中创建对象的方法。
-->
<bean id="instancFactory" class="com.xszx.factory.InstanceFactory"></bean>
<bean id="accountService"
factory-bean="instancFactory"
factory-method="createAccountService"></bean>
bean标签详解
id:对象名称
class:需要创建对象类的全限定类名
name:映射路径名称
scope:scope
属性是bean
标签的一个重要属性,它用于定义Bean的作用范围或生命周期。
- Singleton(单例)
- 默认值:如果不指定
scope
属性,Bean的默认作用域就是Singleton。 - 特点:在Spring IoC容器中,无论通过何种方式(如构造函数注入、Setter方法注入等)请求该Bean,容器都只会返回一个共享的实例。这意味着在Spring容器运行期间,该Bean的实例只会被创建一次,并且所有的Bean引用都将指向这个唯一的实例。
- 应用场景:适用于无状态的服务类、工具类或者配置类等,这些类在应用中通常只需要一个实例即可。
- Prototype(原型)
- 特点:每次通过Spring容器请求该Bean时,都会创建一个新的Bean实例。这意味着每次调用
getBean()
方法时,都会得到一个新的对象实例。 - 应用场景:适用于需要保持状态的Bean,或者有可能在并发环境中产生问题的Bean。例如,数据对象(DTOs)、请求处理对象等。
- Request(请求)
- 特点:该作用域仅适用于Web应用程序。每次HTTP请求都会创建一个新的Bean实例,并且该Bean实例仅在当前HTTP请求内有效。当请求结束时,Bean实例将被销毁。
- 应用场景:在Web应用中,每个HTTP请求都需要一个独立的Bean实例,例如用户的跟踪状态或者临时存储用户信息。
- Session(会话)
- 特点:同样仅适用于Web应用程序。每次HTTP Session都会创建一个新的Bean实例,并且该Bean实例仅在当前HTTP Session内有效。当Session结束时,Bean实例将被销毁。
- 应用场景:在Web应用中,Bean的生命周期绑定到用户的HTTP Session,适用于用户登录后的会话信息,如购物车、用户偏好设置等。
- Application(应用)
- 特点:在Web应用程序的生命周期内,只创建一个Bean实例。Bean以全局方式存在于ServletContext级别,即在整个Web应用中共享一个Bean实例。
- 应用场景:适用于全局的缓存数据或者应用级别的配置,如应用配置、缓存管理器等。
- Websocket(WebSocket会话)
- 特点:在WebSocket的生命周期内,只创建一个Bean实例。Bean的生命周期与WebSocket会话相关联,适用于需要在WebSocket会话期间保持状态的组件。
- 应用场景:在WebSocket通信中,用于存储WebSocket连接的用户信息、游戏状态等。
注意事项
request
、session
、application
和websocket
这四种作用域只有在你的应用是一个Web应用时才适用,因为它们依赖于Servlet容器的上下文。- 正确选择Bean的作用域对于优化应用性能、管理资源和确保线程安全至关重要。例如,使用Singleton作用域可以减少实例化对象的开销,但在多线程环境中可能需要额外的同步措施;而Prototype作用域可以提供每个请求独立的Bean实例,从而避免线程安全问题,但可能会增加对象创建的开销。
factory-bean:工厂bean名称
factory-method:工厂方法
lazy-init:懒加载配置 默认false
注解方式
第一步 追加命名空间在bean.xml中
<?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
">
<!--开启注解驱动-->
<context:annotation-config></context:annotation-config>
<!-- 开启组件扫描-->
<context:component-scan base-package="com.xszx"></context:component-scan>
</beans>
第一套注解(通用注解)
@Component
类似于控制反转
第二套注解(个性化注解)
@Controller
@Service
@Repository
依赖注入的实现方式(DI)
XML方式
set方法注入
1.手动注入
private UserService userService ;
private int age;
public void setAge(int age) {
this.age = age;
}
public void setUserService(UserService userService) {
this.userService = userService;
}
<bean class="com.xszx.controller.UserController" id="userController">
<property name="userService" ref="userService"/>
<property name="age" value="25"></property>
</bean>
2.自动注入
在Spring框架中,自动装配(Autowiring)是一种减少手动配置工作量的方式,它允许Spring容器自动地将bean之间的依赖关系连接起来。你提到的byName
和byType
是自动装配的两种主要模式。下面我会详细解释这两种模式的工作原理和适用场景。
byName 自动装配
在byName
自动装配模式下,Spring容器会查看一个bean的依赖关系,并尝试通过依赖项的属性名(假设该属性有相应的setter方法)来查找与bean ID相匹配的另一个bean。这意呀着,如果一个bean有一个类型为UserService
的属性,并且这个属性的名称(在Java中通常是以getter和setter方法的形式定义的,如setUserService
)或者JavaBean属性名(通常是首字母小写,如userService
)能够直接映射到一个Spring容器中已注册的bean的ID,那么Spring就会尝试将这个bean注入到这个属性中。
示例:
<!-- 定义一个名为userService的bean -->
<bean id="userService" class="com.xszx.service.UserService"/>
<!-- UserController依赖userService,通过byName自动装配 -->
<bean class="com.xszx.controller.UserController" id="userController" autowire="byName">
<!-- 通常不需要显式地声明userService属性,但为了清晰起见,可以这样声明 -->
<property name="userService" ref="userService"/>
</bean>
在UserController
类中,应该有一个名为userService
的属性(或者至少有一个名为setUserService
的setter方法),Spring将自动将ID为userService
的bean注入到这个属性中。
byType 自动装配
在byType
自动装配模式下,Spring容器会查看一个bean的依赖关系,并尝试在Spring容器中查找与该依赖项类型相匹配的bean。如果有多个bean匹配这个类型,Spring容器会抛出一个异常,因为它不能确定使用哪一个bean。这意味着依赖项的类型必须在Spring容器中是唯一的(或者你使用了某种形式的限定符来区分它们)。
示例:
<!-- 定义一个UserService类型的bean -->
<bean class="com.xszx.service.UserService"/>
<!-- UserController依赖UserService,通过byType自动装配 -->
<bean class="com.xszx.controller.UserController" id="userController" autowire="byType"/>
在UserController
类中,应该有一个类型为UserService
的属性(或者至少有一个接受UserService
类型参数的setter方法)。Spring将自动将类型为UserService
的bean注入到这个属性中。
注意事项
- 过度使用自动装配可能会导致依赖关系变得不明显,增加维护难度。
- 在使用
byType
自动装配时,需要确保类型的唯一性,否则会遇到配置冲突。 byName
和byType
各有利弊,应根据具体情况选择使用。- 除了
byName
和byType
,Spring还提供了constructor
和no
(即不自动装配)等选项,以及基于注解的自动装配方式(如@Autowired
),它们提供了更灵活和强大的依赖注入能力。
构造方法注入
1.手动注入
private UserService userService;
private int age;
public UserController() {
}
public UserController(UserService userService, int age) {
this.userService = userService;
this.age = age;
}
<bean class="com.xszx.service.impl.UserServiceImpl02" id="userService"/>
<bean class="com.xszx.controller.UserController" id="userController">
<constructor-arg name="age" value="25"></constructor-arg>
<constructor-arg name="userService" ref="userService"></constructor-arg>
</bean>
2.自动注入
<bean class="com.xszx.controller.UserController" id="userController" autowire="constructor">
</bean>
注解方式
第一套注解(通用注解)
@Autowired
默认安装类型注入
第二套注解(个性化注解)
@Resource
默认按照名字注入 如果没有名字则安装类型注入