这是学习黑马程序SSM的课程笔记,这小节主要是IoC(控制反转)+DI(依赖注入)的介绍
原视频地址:https://www.bilibili.com/video/BV1Fi4y1S7ix
Spring Framework系统架构
Spring Framework是一个开源的Java应用程序框架,它提供了广泛的功能和工具,用于构建企业级Java应用程序。Spring的系统架构是一个分层的体系结构,它包括多个模块和组件,用于不同的功能,以下是Spring Framework的主要系统架构组成部分:详见黑马程序员视频。
核心概念
IOC
控制反转:由主动new产生对象转换为由外部提供对象,对象的创建控制权由程序转移到外部,这种思想叫控制反转。
Spring
对IoC
思想进行了实现:
利用
入门案例
Bean的实例化
在Spring框架中,Bean的实例化可以通过以下方式进行:
-
使用构造函数实例化:这是最常见的方式,Spring会调用Bean类的构造函数来创建Bean的实例。你可以在Spring的配置文件中定义Bean的构造函数参数以及对应的值或引用。
<bean id="myBean" class="com.example.MyBean"> <constructor-arg value="parameterValue" /> </bean>
-
使用静态工厂方法实例化:你可以通过调用Bean类的静态工厂方法来创建Bean的实例。
<bean id="myBean" class="com.example.MyBeanFactory" factory-method="createInstance" />
-
使用实例工厂方法实例化:你可以使用一个普通的Bean作为工厂,通过调用工厂Bean的方法来创建Bean的实例。
<bean id="myFactory" class="com.example.MyBeanFactory" /> <bean id="myBean" factory-bean="myFactory" factory-method="createInstance" />
-
使用FactoryBean实例化:你可以定义一个实现了
org.springframework.beans.factory.FactoryBean
接口的Bean,通过实现getObject()
方法来自定义Bean的创建逻辑。<bean id="myFactoryBean" class="com.example.MyFactoryBean" /> <bean id="myBean" factory-bean="myFactoryBean" />
-
使用注解标记:通过在Java类上使用Spring注解(如
@Component
、@Service
、@Repository
等),Spring会自动扫描并实例化这些被标记的类。@Component public class MyBean { // ... }
上述方式中,使用构造函数或工厂方法实例化是最常见的方式,而使用注解标记的方式是更加方便的方式,尤其在基于注解的Spring应用程序中。不同的实例化方式适用于不同的情况和需求,你可以根据项目的具体要求选择合适的方式。以下是一个简单的示例,包括一个自定义Bean(MyBean
)和一个自定义FactoryBean(MyFactoryBean
),以及Spring配置文件来配置它们。
首先,创建一个名为 MyBean
的Java类,作为自定义Bean:
public class MyBean {
private String message;
public MyBean(String message) {
this.message = message;
}
public void showMessage() {
System.out.println("Message from MyBean: " + message);
}
}
接下来,创建一个自定义的FactoryBean类 MyFactoryBean
,实现 FactoryBean
接口:
import org.springframework.beans.factory.FactoryBean;
public class MyFactoryBean implements FactoryBean<MyBean> {
private String message;
public void setMessage(String message) {
this.message = message;
}
@Override
public MyBean getObject() throws Exception {
return new MyBean(message);
}
@Override
public Class<?> getObjectType() {
return MyBean.class;
}
@Override
public boolean isSingleton() {
return true; // 返回true表示MyBean是单例的
}
}
在上面的代码中,MyFactoryBean
类实现了 FactoryBean
接口,它的 getObject()
方法负责创建并返回 MyBean
实例。
接下来,创建Spring的配置文件(通常是XML文件),用于配置 MyBean
和 MyFactoryBean
:
<!-- 配置自定义Bean MyBean -->
<bean id="myBean" class="com.example.MyBean">
<constructor-arg value="Hello, Spring!" />
</bean>
<!-- 配置自定义FactoryBean MyFactoryBean -->
<bean id="myFactoryBean" class="com.example.MyFactoryBean">
<property name="message" value="This is a message from MyFactoryBean." />
</bean>
<!-- 使用MyFactoryBean创建MyBean实例 -->
<bean id="myBeanFromFactory" factory-bean="myFactoryBean" factory-method="getObject" />
上述配置文件中,首先配置了 myBean
,然后配置了 myFactoryBean
,最后使用 myFactoryBean
创建了一个名为 myBeanFromFactory
的Bean。
现在,当Spring容器启动时,它将根据这些配置来实例化 MyBean
和 MyFactoryBean
,并且可以使用 myBeanFromFactory
访问由 MyFactoryBean
创建的 MyBean
实例。
一旦你的Spring容器实例化了Bean,你就可以通过Spring容器来获取并调用这些Bean。以下是如何在Spring中获取和调用Bean的示例:
假设你有一个Spring容器,可以通过以下方式获取和调用Bean:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
// 初始化Spring容器并加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
// 获取MyBean
MyBean myBean = (MyBean) context.getBean("myBean");
// 调用MyBean的方法
myBean.showMessage();
// 获取MyBeanFromFactory(通过FactoryBean创建的Bean)
MyBean myBeanFromFactory = (MyBean) context.getBean("myBeanFromFactory");
// 调用MyBeanFromFactory的方法
myBeanFromFactory.showMessage();
// 关闭Spring容器(可选)
((ClassPathXmlApplicationContext) context).close();
}
}
在上述示例中:
-
我们首先初始化了一个Spring容器
ApplicationContext
,并加载了配置文件spring-config.xml
。配置文件中包含了我们之前配置的MyBean
和MyFactoryBean
。 -
使用容器的
getBean
方法可以根据Bean的名称获取对应的Bean实例。例如,我们通过context.getBean("myBean")
获取了MyBean
实例,通过context.getBean("myBeanFromFactory")
获取了MyBeanFromFactory
实例。 -
一旦获取了Bean实例,就可以通过实例调用其方法。在示例中,我们分别调用了
MyBean
和MyBeanFromFactory
的showMessage
方法。 -
最后,我们可以选择关闭Spring容器,释放资源。这是可选的,但在实际应用中,通常建议在不再需要Spring容器时关闭它。
总之,通过Spring容器的 getBean
方法获取Bean实例,然后就可以像调用普通Java对象一样调用Bean的方法。Spring容器会负责创建和管理这些Bean,以及处理它们的依赖关系。
Bean的生命周期
依赖注入
构造注入和Setter注入
依赖自动装配
Spring框架提供了依赖自动装配(Dependency Injection)的功能,它是一种通过自动识别和连接Bean之间的依赖关系来简化配置的方式。自动装配可以减少手动配置的工作,提高了代码的可维护性和可读性。在Spring中,有三种主要的自动装配方式:
- 自动装配 by Type(按类型自动装配):Spring会自动将容器中的Bean与目标Bean的属性类型匹配的Bean进行关联。这是默认的自动装配方式。
<bean id="foo" class="com.example.Foo" />
<bean id="bar" class="com.example.Bar" autowire="byType"/>
public class Foo {
private Bar bar;
// ...
}
在上面的示例中,Spring会自动将名为 bar
的Bean注入到 Foo
类的 bar
属性中,因为它们的类型匹配。
- 自动装配 by Name(按名称自动装配):Spring会自动将容器中的Bean与目标Bean的属性名称匹配的Bean进行关联。
<bean id="foo" class="com.example.Foo" />
<bean id="bar" class="com.example.Bar" autowire="byName"/>
public class Foo {
private Bar bar;
// ...
}
在上面的示例中,Spring会自动将名为 bar
的Bean注入到 Foo
类的 bar
属性中,因为它们的名称匹配。
- 自动装配 by Constructor(按构造函数自动装配):Spring会自动将容器中的Bean与目标Bean的构造函数参数类型匹配的Bean进行关联。
<bean id="foo" class="com.example.Foo" />
<bean id="bar" class="com.example.Bar" />
public class Foo {
private Bar bar;
public Foo(Bar bar) {
this.bar = bar;
}
// ...
}
在上面的示例中,Spring会自动将名为 bar
的Bean注入到 Foo
类的构造函数中,因为它们的类型匹配。
要启用自动装配,你可以在Spring配置文件中使用 <context:annotation-config />
元素来激活自动装配功能。另外,你也可以使用注解方式,如 @Autowired
,来标记需要自动装配的属性、构造函数或方法。
以下是一个使用注解方式实现自动装配的示例:
import org.springframework.beans.factory.annotation.Autowired;
public class Foo {
private Bar bar;
@Autowired
public Foo(Bar bar) {
this.bar = bar;
}
// ...
}
在上面的示例中,@Autowired
注解标记了 Foo
类的构造函数,告诉Spring容器在创建 Foo
实例时自动注入名为 bar
的Bean。要使用注解方式进行自动装配,你需要确保已经启用了组件扫描(component scanning)和注解驱动(annotation-driven)的功能。通常,你可以在Spring配置文件中添加以下配置:
<context:component-scan base-package="com.example" />
<context:annotation-config />
这样,Spring容器会自动扫描指定包中的类,查找标有注解的类,并进行自动装配。
集合注入
集合注入是指在Spring容器配置文件中,将一组对象作为集合注入到一个Bean中。Spring支持多种类型的集合注入,包括List、Set、Map等。这可以在配置文件中通过标签和属性来实现。
以下是一些示例,演示如何在Spring中进行集合注入:
1. List注入:
假设你有一个名为 MyBean
的Bean,需要注入一个List类型的集合属性:
<bean id="myBean" class="com.example.MyBean">
<property name="myList">
<list>
<value>Item 1</value>
<value>Item 2</value>
<value>Item 3</value>
</list>
</property>
</bean>
在这个示例中,我们使用 <list>
元素来定义一个List,并在其中包含了三个字符串值。
public class MyBean {
private List<String> myList;
public void setMyList(List<String> myList) {
this.myList = myList;
}
// ...
}
MyBean
类中有一个名为 myList
的List属性,通过Spring容器的属性注入,它将包含上面配置的三个字符串值。
2. Set注入:
与List注入类似,Set注入也是通过 <set>
元素来实现的。配置方式与上面的List示例类似,只需将 <list>
替换为 <set>
。
3. Map注入:
如果你需要注入一个Map类型的集合属性,可以使用 <map>
元素来定义Map。以下是一个示例:
<bean id="myBean" class="com.example.MyBean">
<property name="myMap">
<map>
<entry key="Key1" value="Value1"/>
<entry key="Key2" value="Value2"/>
</map>
</property>
</bean>
在这个示例中,我们使用 <map>
元素来定义一个Map,其中包含了两个键值对。
public class MyBean {
private Map<String, String> myMap;
public void setMyMap(Map<String, String> myMap) {
this.myMap = myMap;
}
// ...
}
MyBean
类中有一个名为 myMap
的Map属性,通过Spring容器的属性注入,它将包含上面配置的两个键值对。
这些示例演示了如何在Spring配置文件中注入集合类型的属性。Spring会负责创建集合并将其注入到相应的Bean中。你可以根据实际需求选择List、Set、Map等不同的集合类型,并在配置文件中定义它们的内容。