bean的实例化
1.通过构造方法实例化
1.Spring通过setter方法往bean里注入他依赖的bean。所以记得提供提供对应的setter方法
package com.example;
public class MyClass {
MyOtherClass myOtherClass;
public void setMyOtherClass(MyOtherClass myOtherClass)
{
this.myOtherClass=myOtherClass;
}
public void run(){
myOtherClass.run();
}
}
1.定义一个SpringConfiguration XML文件
<?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 name属性是bean的别名,可多个,使用, ; 空格 分隔-->
<bean id="myOtherBean" name="name1 name2 name3 " class="com.example.MyOtherClass">
<!-- 可以在这里设置myOtherBean的属性 -->
</bean>
<!-- 定义一个简单的Bean,依赖于myOtherBean -->
<bean id="myBean" class="com.example.MyClass">
<!-- property name代表给哪个属性赋值,ref标识给这个属性赋值哪个名字的bean -->
<property name="propertyName" ref="myOtherBean"/>
</bean>
</beans>
2.通过静态工厂实例化
通过此方式可以提前进行一些配置
1.创建一个工厂类,里面创建类的实例化方法
public class MyBeanFactory { public static MyClass createMyClass() { system.out.println("这里开始你的配置") return new MyClass("初始化参数"); } }
2.在xml文件中配置工厂中的bean
<bean id="myBean" class="com.example.MyBeanFactory" factory-method="createMyClass"/>
3.通过实例化工厂实例化bean
1. 定义工厂类
首先,创建一个工厂类,这个类包含一个实例方法,该方法返回要创建的Bean对象。
public class MyBeanFactory { public MyClass createMyClass() { return new MyClass("初始化参数"); } }
2. 在Spring配置中定义Bean
接下来,在Spring的配置文件(如XML配置)中,定义工厂类的Bean和使用工厂方法创建的Bean。
<bean id="myBeanFactory" class="com.example.MyBeanFactory"/> <bean id="myBean" factory-bean="myBeanFactory" factory-method="createMyClass"/>
4.通过继承FactoryBean接口实例化bean
1. 实现
FactoryBean
接口首先,你需要创建一个类实现
FactoryBean
接口。该接口要求实现三个方法:getObject()
、getObjectType()
和isSingleton()
。import org.springframework.beans.factory.FactoryBean; public class MyBeanFactory implements FactoryBean<MyClass> { @Override public MyClass getObject() throws Exception { // 创建并返回Bean实例 return new MyClass("初始化参数"); } @Override public Class<?> getObjectType() { // 返回Bean的类型 return MyClass.class; } @Override public boolean isSingleton() { // 指示该Bean是否为单例 return true; } }
<bean id="myBean" class="com.example.MyBeanFactory"/>
bean的生命周期
在XML配置中,使用<bean>
元素定义Bean。常用的属性包括:
class
:指定Bean的实现类。id
:给Bean命名,便于在其他地方引用。init-method
:指定初始化方法的名称。destroy-method
:指定销毁方法的名称。
1.创建bean类
package com.example;
public class MyBean {
public void initMethod() {
System.out.println("MyBean 初始化");
}
public void destroyMethod() {
System.out.println("MyBean 销毁");
}
}
2. 编写XML配置文件
<bean id="myBean" class="com.example.MyBean"
init-method="initMethod"
destroy-method="destroyMethod"/>
</beans>
摧毁操作要关闭容器才会执行到。
public class MainApp {
public static void main(String[] args) {
// 加载Spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
context.registerShootDownHook;//关闭虚拟机前关闭容器
// 获取Bean
MyBean myBean = (MyBean) context.getBean("myBean");
// 在这里可以使用myBean
// ...
// 关闭上下文
// context.close(); // 这将调用destroyMethod,暴力方法
}
}
还可以通过实现接口重写方法的方式来固定配置格式
1.InitializingBean
接口
当你实现InitializingBean
接口时,需要重写afterPropertiesSet()
方法,这个方法在Bean的所有属性设置完毕后调用,适合放置初始化逻辑。
2. DisposableBean
接口
实现DisposableBean
接口需要重写destroy()
方法,此方法在Bean被销毁时调用,适合放置清理逻辑。
public class MyBean implements InitializingBean, DisposableBean {
private String message;
public void setMessage(String message) {
this.message = message;
}
@Override
public void afterPropertiesSet() throws Exception {
// 初始化逻辑
System.out.println("MyBean 初始化: " + message);
}
@Override
public void destroy() throws Exception {
// 清理逻辑
System.out.println("MyBean 销毁");
}
}
bean的属性注入
1.setter方法注入
public class MyBean {
private String dependency;
// 提供setter方法
public void setDependency(Stringdependency) {
this.dependency = dependency;
}
}
<bean id="myBean" class="com.example.MyBean">
<property name="dependency" value="你好啊"/><!...基本数据类型使用value注入..>
</bean>
2.构造方法注入
package com.example;
public class MyBean {
private Dependency dependency;
// 构造方法
public MyBean(Dependency dependency) {
this.dependency = dependency;
}
public void execute() {
dependency.doSomething();
}
}
<bean id="dependency" class="com.example.Dependency"/>
<bean id="myBean" class="com.example.MyBean">
<constructor-arg ref="dependency"/>
</bean>
如果你的构造函数有多个参数,你可以通过 name
指定参数名称:
<constructor-arg name="dependency" ref="dependency"/>
<constructor-arg name="anotherDependency" ref="anotherDependency"/>
自动装配
使用自动装配就不用手动的配置此bean的依赖bean。
基本用法
- 按类型自动装配
xmlCopy Code
<bean id="myBean" class="com.example.MyBean" autowire="byType"/>
在这种情况下,Spring会查找类型为 MyBean
的构造函数参数,并自动注入匹配的 Bean。
- 按名称自动装配
xmlCopy Code
<bean id="myBean" class="com.example.MyBean" autowire="byName"/>
在此情况下,Spring会查找与 Bean ID 匹配的名称并进行注入。
注意:还是要提供对应的setter方法。
集合注入
在Spring的XML配置中,注入集合属性(如列表、集合、映射等)是一个常见的需求。以下是如何通过XML配置注入集合属性的几种方式:
1. 注入列表(List)
<bean id="myBean" class="com.example.MyBean">
<property name="myList">
<list>
<value>Item1</value>
<value>Item2</value>
<value>Item3</value>
</list>
</property> </bean>
2. 注入集合(Set)
<bean id="myBean" class="com.example.MyBean">
<property name="mySet">
<set>
<value>ItemA</value>
<value>ItemB</value>
<value>ItemC</value>
</set>
</property>
</bean>
3. 注入映射(Map)
<bean id="myBean" class="com.example.MyBean">
<property name="myMap">
<map>
<entry key="key1" value="value1"/>
<entry key="key2" value="value2"/>
<entry key="key3" value="value3"/>
</map>
</property>
</bean>
示例类
假设我们有一个类 MyBean
,其中包含一个列表、一个集合和一个映射
public class MyBean {
private List<String> myList;
private Set<String> mySet;
private Map<String, String> myMap;
// setters
public void setMyList(List<String> myList) {
this.myList = myList;
}
public void setMySet(Set<String> mySet) {
this.mySet = mySet;
}
public void setMyMap(Map<String, String> myMap) {
this.myMap = myMap;
}
// 方法来打印集合内容
public void printCollections() {
System.out.println("List: " + myList);
System.out.println("Set: " + mySet);
System.out.println("Map: " + myMap);
}
}
配置文件
当我们要使用外部类进行属性配置时,例如要连接数据库,这时候我们要将数据库的类交给IOC容器管理,并且给类中的属性,例如用户名,密码等数据项进行配置时,我们通过属性注入的方式进行配置,但是最好这些配置属性能抽离出来,于是我们把他放到配置文件中,xml配置中只要引用properties属性值即可注入。
1.创建properties文件
service.url=http://example.com/api
2.我们在xml文件中首先开启context命名空间。并加载配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
//第一个配置点
xmlns:context="http://www.springframework.org/schema/context"
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">
//加载配置文件属性,location多个属性可用逗号分隔
<context:property-placeholder location="classpath:application.properties"/>
<context:component-scan base-package="com.example"/>
</beans>
3.配置bean属性,通过表达式引用properties
<bean id="thirdPartyService" class="com.example.ThirdPartyService">
<property name="url" value="${service.url}"/>
</bean>
注解开发
注解开发直接在类上加上@Component注解即可替代XML配置bean。但是需要spring去扫描这个注解才能使用。
于是XML文件中需要配置扫描包Component-scan组件的扫描范围。
<context:component-scan base-package="com.example"/>
Spring3.0开启了纯注解开发。使用java配置类代替配置文件。
1.定义一个配置类,上面加上@Configuration注解指明他是配置类
-
@Configuration:标记一个类为配置类,它可以包含 Bean 的定义,但仅仅使用
@Configuration
并不会触发组件扫描。 -
@ComponentScan:如果需要扫描特定包中的组件,需要在配置类中显式添加
@ComponentScan
注解。这个注解的作用是告诉 Spring 在指定的包中查找带有特定注解的类并将其注册为 Spring 的 Bean。 -
默认行为:如果没有配置
@ComponentScan
,Spring 会扫描配置类本身所在的包(及其子包),但这仅限于配置类本身,并不会扫描其他类。
@ComponentScan指定包中组件扫描范围
@PropertySource // 加载properties文件
@Configuration
@ComponentScan(basePackages = "com.example") // 自动扫描指定包中的组件
@PropertySource("classpath:application.properties") // 加载properties文件
public class AppConfig {
}
在主程序中,可以使用AnnotationConfigApplicationContext
来获取容器:
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
ThirdPartyService service = context.getBean(ThirdPartyService.class);
// 使用service
}
}
bean的作用范围
pring中Bean的作用范围(Scope)决定了Bean的创建和生命周期。常见的作用范围包括:
-
singleton(单例):
- 默认作用域。
- Spring容器只会创建一个Bean实例,并在整个应用上下文中共享这个实例。
@Bean @Scope("singleton") public MyBean myBean() { return new MyBean(); }
-
prototype(原型):
- 每次请求都会创建一个新的Bean实例。
- 对于每个
getBean()
调用,Spring容器会返回一个新的实例。
@Bean @Scope("prototype") public MyBean myBean() { return new MyBean(); }
bean的生命周期
在Spring框架中,Bean的生命周期可以通过多种注解进行管理,主要包括以下几种注解:
1. @PostConstruct
-
用途:用于标注在一个方法上,表示该方法将在Bean的依赖注入完成后被调用。可以用于执行初始化逻辑。
-
使用示例:
public class MyBean { @PostConstruct public void init() { // 初始化逻辑 System.out.println("Bean is initialized"); } }
2. @PreDestroy
-
用途:用于标注在一个方法上,表示该方法将在Bean被销毁之前被调用。可以用于执行清理工作。
-
使用示例:
public class MyBean { @PreDestroy public void cleanup() { // 清理逻辑 System.out.println("Bean is being destroyed"); } }
3. @Bean(initMethod = "methodName")
和 @Bean(destroyMethod = "methodName")
-
用途:在
@Configuration
类中定义Bean时,可以通过这两个属性指定初始化和销毁的方法。 -
使用示例:
@Configuration public class AppConfig { @Bean(initMethod = "init", destroyMethod = "cleanup") public MyBean myBean() { return new MyBean(); } } public class MyBean { public void init() { // 初始化逻辑 } public void cleanup() { // 清理逻辑 } }
依赖注入
@Autowired
使用@Autowired注解。不需要提供对应setter方法,他通过暴力反射给属性注入值。可以用于构造器、字段和方法。
@Component
public class UserService {
private final UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
// 业务逻辑方法
}
@Qualifier
用途:在存在多个相同类型的Bean时,结合@Autowired
使用,以指定具体的Bean。
@Component
public class UserService {
private final UserRepository userRepository;
@Autowired
public UserService(@Qualifier("specificUserRepository") UserRepository userRepository) {
this.userRepository = userRepository;
}
}
@Value
用途:用于注入外部化配置,如properties文件中的值。记得要在spring配置文件上加注解@PropertySource("classpath:application.properties") // 加载properties文件
@Component
public class AppConfig {
@Value("${app.name}")
private String appName;
// Getter和Setter
}
管理第三方bean
当我们要管理第三方bean时,不能在别人的代码上加上注解,于是可以把他放到配置类中。
通过@Bean注解方式来定义bean。将当前方法的返回值对象交给IOC容器进行管理。通过注解的name/value属性指定bean名称,默认为方法名。
@Configuration
public class CommonConfig {
//声明bean对象
@Bean
public SAXReader saxReader(){
return new SAXReader();
}
第三方bean想要进行依赖注入,直接在方法中指定形参即可。
@Configuration
public class CommonConfig {
//声明bean对象
@Bean
public SAXReader saxReader(Service service){
service.方法;
return new SAXReader();
}
但是如果把他放到spring的配置类里,显得不是那么回事儿,这是第三方配置类,跟spring没关系。于是我们把他放到另一个文件中。
方式一:
这时候可以自己定义另一个配置类,上面加上@Configuration注解。
方式二:
在配置类上使用@Import注解,它能够导入其他配置类或者 普通类。将类加入IOC容器中
@Configuration
@Import(OtherConfig.class) // 导入其他配置类
public class MainConfig {
// Bean 定义
}
答疑:
问:不使用componentScan,他会扫描到配置类吗?
答:使用
@Configuration
注解的类会被注册,但前提是这些类在主应用类所在包或通过其他方式(如@Import
)被显式提及。(例如主类通过注解获取IOC容器)。问:@ComponentScan 注解会去注册配置类吗
答:是的,
@ComponentScan
注解会注册指定包及其子包中的所有 Spring 组件,包括配置类(使用@Configuration
注解的类)、服务类(使用@Service
注解的类)、控制器类(使用@Controller
注解的类)等。问:也就是说,spring配置类假如被主类提及,那他包下的其他configuration配置类也会被注册吗
答:默认行为:这是因为
@ComponentScan
默认只扫描配置类所在的包及其子包。问:@Import注解他能把普通类注册到IOC容器中,不需要CompontentScan扫描吗
答:是的,
@Import
确实可以将普通类注册到 Spring 的 IOC 容器中,而不需要通过@ComponentScan
进行扫描。