组件和组件管理概念
组件可以完全交给Spring 框架进行管理,Spring框架替代了程序员原有的new对象和对象属性赋值动作等!我们只需要编写元数据(配置文件)告知Spring 管理哪些类组件和他们的关系即可。组件是对象,对象不一定是组件。简单说,组件就是可复用的Java对象
综上所述,Spring 充当一个组件容器,创建、管理、存储组件,使得可以通过配置的方式使用或改造组件,减少了我们的编码压力,让我们更加专注进行业务编写!
Spring 容器,又叫IoC容器
简单容器只能用来存储,比如数组等,复杂容器能够管理一生,比如springioc容器,不仅要负责创建组件中的对象,存储组件的对象,还要负责调用组件的方法让他们工作,最终在特定情况下销毁组件
Spring IoC 容器,负责实例化、配置和组装 bean(组件)。容器通过读取配置元数据来获取有关要实例化、配置和组装组件的指令。配置元数据以 XML、Java 注解或 Java 代码形式表现。它允许表达组成应用程序的组件以及这些组件之间丰富的相互依赖关系。
IoC 容器具体接口和实现类
`BeanFactory` 接口提供了一种高级配置机制,能够管理任何类型的对象,它是SpringIoC容器标准化超接口!
`ApplicationContext` 是 `BeanFactory` 的子接口。它扩展了以下功能:
- 更容易与 Spring 的 AOP 功能集成
- 消息资源处理(用于国际化)
- 特定于应用程序给予此接口实现,例如Web 应用程序的 `WebApplicationContext`
简而言之, `BeanFactory` 提供了配置框架和基本功能,而 `ApplicationContext` 添加了更多特定于企业的功能。 `ApplicationContext` 是 `BeanFactory` 的完整超集!
IoC 容器管理配置的方式
Spring框架提供了多种配置方式:XML配置方式、注解方式和Java配置类方式
1. XML配置方式:是Spring框架最早的配置方式之一,通过在XML文件中定义Bean及其依赖关系、Bean的作用域等信息,让Spring IoC容器来管理Bean之间的依赖关系。该方式从Spring框架的第一版开始提供支持。
2. 注解方式:从Spring 2.5版本开始提供支持,可以通过在Bean类上使用注解来代替XML配置文件中的配置信息。通过在Bean类上加上相应的注解(如@Component, @Service, @Autowired等),将Bean注册到Spring IoC容器中,这样Spring IoC容器就可以管理这些Bean之间的依赖关系。
3. **Java配置类**方式:从Spring 3.0版本开始提供支持,通过Java类来定义Bean、Bean之间的依赖关系和配置信息,从而代替XML配置文件的方式。Java配置类是一种使用Java编写配置信息的方式,通过@Configuration、@Bean等注解来实现Bean和依赖关系的配置。
Spring IoC 容器的核心功能——IoC/DI
IoC控制反转:从应用程序创建对象到IoC容器创建对象,也就是反转了控制权,这种现象就是控制反转
DI依赖注入:把对象2注入到对象1 中,也可以说是对象1 需要用 对象 2。可以通过构造函数或setter方法或接口注入
IoC/DI都发生在IoC 容器内
Spring IoC/DI 实现步骤
1/配置元数据
2/实例化IoC容器
3/获取Bean(组件)
基于XML配置方式组件管理
IoC配置
public class HappyComponent {
//默认包含无参数构造函数
public void doWork() {
System.out.println("HappyComponent.doWork");
}
}
/**
* @author Xin
* @date 2025/2/17 00:01:26
* @note 静态工厂
*/
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService() {}
public static ClientService createInstance() {
return clientService;
}
}
/**
* @author Xin
* @date 2025/2/17 00:05:53
* @note 实例工厂,非静态工厂
*/
public class DefaultServiceLocator {
private static ClientServiceImpl clientService = new ClientServiceImpl();
public ClientServiceImpl createClientServiceInstance() {
return clientService;
}
}
<?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">
<!--可以使用无参构造函数实例化的组件,如何进行IOC配置-->
<bean id="happyComponent" class="com.xin.ioc_01.HappyComponent" />
<!--静态工厂类如何进行IOC配置,factory-method = "静态工厂方法"-->
<bean id="clientService" class="com.xin.ioc_01.ClientService" factory-method="createInstance" />
<!--非静态工厂类如何进行IOC配置-->
<!--1/配置工厂类的组件信息;2/通过指定非静态工厂对象和方法名来配置生成的ioc-->
<bean id="defaultServiceLocator" class="com.xin.ioc_01.DefaultServiceLocator"/>
<bean id="clientService2" factory-bean="defaultServiceLocator" factory-method="createClientServiceInstance"/>
</beans>
DI配置
public class UserDao {
}
public class UserService {
private UserDao userDao;
private int age;
private String name;
public UserService(int age , String name , UserDao userDao){
this.userDao = userDao;
this.age = age;
this.name = name;
}
}
<?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">
<!--构造方法注入-->
<!--引用和被引用的组件,必须都在ioc容器中-->
<!--bean其实是调用的无参构造函数,所以一定要有无参构造函数才能用,否则要传值-->
<bean id="userDao" class="com.xin.ioc_02.UserDao"></bean>
<!--将userDao通过构造函数注入到userService-->
<bean id="userService" class="com.xin.ioc_02.UserService">
<!--构造参数传值 di 的配置-->
<!--constructor-arg 构造参数传值的di配置,value = “直接属性值”, ref = 引用的其他bean,只能二选一-->
<constructor-arg ref="userDao"></constructor-arg>
<constructor-arg name="name" value="南星沐" />
<constructor-arg name="age" value="24"/>
<!-- 也可以省略name属性,直接按顺序填写-->
<!-- <constructor-arg ref="userDao"></constructor-arg>-->
<!-- <constructor-arg value="24"/>-->
<!-- <constructor-arg value="南星沐" />-->
<!-- 也可以按下角标,从左到右,从0开始-->
<!-- <constructor-arg index = "0" ref="userDao"></constructor-arg>-->
<!-- <constructor-arg index = "1" value="24"/>-->
<!-- <constructor-arg index = "2" value="南星沐" />-->
</bean>
<!--springioc是一个高级容器,内部会有缓存动作,先创建对象,再进行属性赋值,所以两个bean先后顺序均可-->
</beans>
容器创建和获取bean
<?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配置是进行组件信息的ioc配置,只有被 allicationContext 读取了,才是实例化对象-->
<!-- 触发setter方法进行注入 -->
<bean id="movieFinder" class="com.xin.ioc_02.MovieFinder" />
<bean id="simpleMovieLister" class="com.xin.ioc_02.SimpleMovieLister">
<!--name = "属性值" , 其实就是set方法去set和首字母小写的值,本质是调用了set方法-->
<property name="movieFinder" ref="movieFinder"/>
<property name="movieName" value="南星沐"/>
</bean>
</beans>
public class SpringIocTest {
// 如何创建ioc容器并且读取配置文件
public void createIoc(){
// 方式1:直接构造函数(String...配置文件)
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-03.xml");
// // 方式2:先创建,再指定配置文件,再刷新
// ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext();
// classPathXmlApplicationContext.setConfigLocations("spring-03.xml");
// classPathXmlApplicationContext.refresh();
}
// 如何再ioc容器中获取组件bean
public void getBeanFromIoc(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-03.xml");
Object movieFinder = applicationContext.getBean("movieFinder");
// object 强转
MovieFinder movieFinder1 = (MovieFinder) movieFinder;
// 方式2
MovieFinder movieFinder2 = applicationContext.getBean("movieFinder", MovieFinder.class);
// 方式3
// 根据bean类型获取组件bean要保证ioc容器中只有一个同类型bean组件,如果存在多个,会出现 noUniqueBeanFinitionException
MovieFinder movieFinder3 = applicationContext.getBean(MovieFinder.class);
}
}