核心容器
核心容器由核心,Bean,上下文和表达式语言模块组成,它们的细节如下:
-
核心模块提供了框架的基本组成部分,包括 IoC 和依赖注入功能。
-
Bean 模块提供 BeanFactory,它是一个工厂模式的复杂实现。
-
上下文模块建立在由核心和 Bean 模块提供的坚实基础上,它是访问定义和配置的任何对象的媒介。ApplicationContext 接口是上下文模块的重点。
- 表达式语言模块在运行时提供了查询和操作一个对象图的强大的表达式语言。
IoC 容器 控制反转
Spring 容器是 Spring 框架的核心。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件。这些对象被称为 Spring Beans
Spring ApplicationContext 容器
1.含义:Application Context 是 spring 中较高级的容器。它可以加载配置文件中定义的 bean,将所有的 bean 集中在一起,当有请求的时候分配 bean
2.ClassPathXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你不需要提供 XML 文件的完整路径,只需正确配置 CLASSPATH 环境变量即可,因为,容器会从 CLASSPATH 中搜索 bean 配置文件。
实际应用:
Sping 的 BeanFactory 容器
这是一个最简单的容器,它主要的功能是为依赖注入 (DI) 提供支持
Bean 定义
被称作 bean 的对象是构成应用程序的支柱也是由 Spring IoC 容器管理的。bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象。这些 bean 是由用容器提供的配置元数据创建的
Spring 依赖注入(DI)
每个基于应用程序的 java 都有几个对象,这些对象一起工作来呈现出终端用户所看到的工作的应用程序。当编写一个复杂的 Java 应用程序时,应用程序类应该尽可能独立于其他 Java 类来增加这些类重用的可能性,并且在做单元测试时,测试独立于其他类的独立性。依赖注入(或有时称为布线)有助于把这些类粘合在一起,同时保持他们独立。
Beans 自动装配
Spring 容器可以在不使用<constructor-arg>
和<property>
元素的情况下自动装配相互协作的 bean 之间的关系,这有助于减少编写一个大的基于 Spring 的应用程序的 XML 配置的数量。
Spring 自动装配 ‘byType’
这种模式由属性类型指定自动装配。Spring 容器看作 beans,在 XML 配置文件中 beans 的 autowire 属性设置为 byType。然后,如果它的 type 恰好与配置文件中 beans 名称中的一个相匹配,它将尝试匹配和连接它的属性。如果找到匹配项,它将注入这些 beans,否则,它将抛出异常。
例如,在配置文件中,如果一个 bean 定义设置为自动装配 byType,并且它包含 SpellChecker 类型的 spellChecker 属性,那么 Spring 就会查找定义名为 SpellChecker 的 bean,并且用它来设置这个属性。你仍然可以使用 <property> 标签连接其余属性
Spring 自动装配 ‘byName’
这种模式由属性名称指定自动装配。Spring 容器看作 beans,在 XML 配置文件中 beans 的 auto-wire 属性设置为 byName。然后,它尝试将它的属性与配置文件中定义为相同名称的 beans 进行匹配和连接。如果找到匹配项,它将注入这些 beans,否则,它将抛出异常。
例如,在配置文件中,如果一个 bean 定义设置为自动装配 byName,并且它包含 spellChecker 属性(即,它有一个 setSpellChecker(...) 方法),那么 Spring 就会查找定义名为 spellChecker 的 bean,并且用它来设置这个属性。
自动装配的局限性
当自动装配始终在同一个项目中使用时,它的效果最好。如果通常不使用自动装配,它可能会使开发人员混淆的使用它来连接只有一个或两个 bean 定义。不过,自动装配可以显著减少需要指定的属性或构造器参数,但你应该在使用它们之前考虑到自动装配的局限性和缺点。
Bean 的作用域
singleton 作用域:
如果作用域设置为 singleton,那么 Spring IoC 容器刚好创建一个由该 bean 定义的对象的实例。该单一实例将存储在这种单例 bean 的高速缓存中,以及针对该 bean 的所有后续的请求和引用都返回缓存对象。
默认作用域是始终是 singleton,但是当仅仅需要 bean 的一个实例时,你可以在 bean 的配置文件中设置作用域的属性为 singleton,如下所示:
<bean id="..." class="..." scope="singleton"> </bean>
prototype 作用域
如果作用域设置为 prototype,那么每次特定的 bean 发出请求时 Spring IoC 容器就创建对象的新的 Bean 实例。一般说来,满状态的 bean 使用 prototype 作用域和没有状态的 bean 使用 singleton 作用域。
<bean id="..." class="..." scope="prototype"> </bean>
Spring Bean 生命周期
理解 Spring bean 的生命周期很容易。当一个 bean 被实例化时,它可能需要执行一些初始化使它转换成可用状态。同样,当 bean 不再需要,并且从容器中移除时,可能需要做一些清除工作。
初始化回调
销毁回调
实际的例子
spring的配置文件xml
<bean id="appUser" class="hanqi.model.AppUesr" p:name="喔喔" p:age="14"> <!-- 属性注入 --> <!-- p标记的使用 --> <property name="name" value="哈哈"></property> <!-- name写的是实体类里面的变量名,Alt+/ 可以出来 --> <!-- setter方法注入 --> <property name="age" value="14"></property> <property name="dept" ref="dept"></property><!-- 将dept对象注入到AppUser对象 --> <constructor-arg index="0" value="小子" ></constructor-arg> <!-- 构造器,类里面要有这个构造方法,按索引来看 --> <constructor-arg index="1" value="45"></constructor-arg> <constructor-arg index="2" ref="nowtime"></constructor-arg> <!-- 关于日期的构造方法 --> <!-- 将dept对象注入到AppUser对象,我不写<property>的话,我用自动装配里面的byType,在<bean autowire="byType"></bean> --> <!-- 还有一种自动装配的方式,byName,这时候里面的id名和里面的实体类里面的变量名一定要相同,才可以找的到的 --> <property name="addlist"> <!-- 集合里面注入 --> <list> <value></value> </list> </property> <property name="map"> <!-- Map里面注入 --> <map> <entry key="" value=""></entry> </map> </property> </bean> <bean id="nowtime" class="java.util.Date"> <!-- 如果用构造器的方法的话,有日期类型的话,就这样写了 --> </bean> <!-- 如果再写一个Dept部门的实体类,里面有deptno部门编号,还有deptname部门名称,在AppUser表里面就有Dept dept 这个成员变量 --> <bean id="dept" class="hanqi.model.Dept"> <property name="deptname" value="市场部"></property> <property name="deptno" value="公关部"></property> </bean>
AppUser 数据模型
public class AppUesr { private String name; private Integer age; private Date birth; private List<String> addlist; public AppUesr() { super(); } public void say() { System.out.println(this.name + ":你好,春天!"); } public AppUesr(String name, Integer age, Date birth) { super(); this.name = name; this.age = age; this.birth = birth; } public AppUesr(String name, Integer age, List<String> addlist) { super(); this.name = name; this.age = age; this.addlist = addlist; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public List<String> getAddlist() { return addlist; } public void setAddlist(List<String> addlist) { this.addlist = addlist; } public Date getBirth() { return birth; } public void setBirth(Date birth) { this.birth = birth; } @Override public String toString() { return "AppUesr [name=" + name + ", age=" + age + ", birth=" + birth + ", addlist=" + addlist + "]"; } }
test.java 加载配置文件里面的bean
public class Test { public static void main2(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("conf/applicationContext.xml");//默认的是src下面的路径 AppUesr obj = (AppUesr)ac.getBean("appUser");//写的是spring配置文件里面的<bean>标签 obj.setName("hahha"); obj.setAge(25); obj.say(); //调用方法 close(ac); } public static void close(ApplicationContext ac) { //关闭资源的方法 ClassPathXmlApplicationContext c =(ClassPathXmlApplicationContext)ac; c.close(); } }
另一种写法 ,持久性框架
public class Test { public static void main(String[] args) { ClassPathXmlApplicationContext c = new ClassPathXmlApplicationContext("conf/applicationContext.xml");//带class的就是在src路径下查找的 AppUser a = c.getBean(AppUser.class); //泛型,直接获取的是这个类 c.close(); } }