1、容器概述
ApplicationContext是Spring IoC容器实现的代表,它负责实例化、配置和组装Bean。容器通过读取配置元数据获取有关实例化、配置和组装哪些对象的说明 。配置元数据可以使用XML、Java注解或Java代码来呈现。它允许你处理应用程序的对象与其他对象之间的互相依赖关系。
1.1 配置元数据(参考上一篇文章)
a、xml配置文件,一撸到底
b、xml和注解混用阶段
c、完全抛弃xml,使用javaConfig的方式进行开发。
1.2 容器的实例化
对象在Spring容器创建完成的时候就已经创建完成,不是需要用的时候才创建
1.3 容器的使用
ApplicationContext是能够创建bean定义以及处理相互依赖关系的高级工厂接口,使用方法
T getBean(String name, Class requiredType)获取容器实例。
// 创建spring上下文 加载所有的bean
ApplicationContext context = new ClassPathXmlApplicationContext("spring-ioc.xml");
// 获取bean
User user = context.getBean("user", User.class);
复制代码
2、bean的概述
2.1 命名bean
<bean class="com.tuling.entity.User" id="user" name="user2 user3,user4;user5"></bean>
<alias name="user" alias="user6"></alias>
复制代码
注意:user、user2、user3、user4、user5、user6是同一个对象
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring-ioc.xml");
User user = (User) context.getBean("user");
User user2 = (User) context.getBean("user2");
User user3 = (User) context.getBean("user3");
User user4 = (User) context.getBean("user4");
System.out.println(user);//com.zhl.entity.User@cb51256
System.out.println(user2);//com.zhl.entity.User@cb51256
System.out.println(user3);//com.zhl.entity.User@cb51256
System.out.println(user4);//com.zhl.entity.User@cb51256
User user6 = (User) context.getBean("user6");
System.out.println(user6);//com.zhl.entity.User@cb51256
}
复制代码
2.2 实例化 Bean
2.2.1 使用构造器实例化(默认)
该方法无法干预实例化过程
2.2.2 使用静态工厂方法实例化
a、配置文件
<bean id="user" class="com.zhl.entity.User" factory-method="createUserInstance"></bean>
复制代码
b、实体类中增加静态工厂方法
public class User {
private Integer id;
private String username;
private String realname;
public User() {
System.out.println("2、创建了一个对象");
}
public static User createUserInstance(){
System.out.println("1、先输出这一句");
return new User();
}
}
复制代码
2.2.3 使用实例工厂方法实例化
a、配置文件
<bean class="com.zhl.entity.User" id="user" factory‐bean="userFactory" factory‐method="createUserFactory" ></bean>
复制代码
b、实例工厂类
public class UserFactory{
public User createUserFactory(){
return new User();
}
}
复制代码
3、依赖
3.1 依赖注入
a、基于setter方法的依赖注入
<!-- 基于setter方法的依赖注入
1. 属性必须声明了set方法
2. name是根据set方法的名字来的 比如方法名字是: setIdxx ‐》 name="idxx"
-->
<bean id="user" class="com.zhl.entity.User">
<property name="id" value="1"></property>
<property name="username" value="一右四分之一"></property>
<property name="realname" value="还是一右四分之一"></property>
</bean>
复制代码
b、基于构造函数的依赖注入
<!--基于构造函数的依赖注入
1. 将会调用自定义构造函数来实例化对象,就不会调用默认的无参构造函数
2. name是根据构造函数的参数名来的, 比如:User(String idxx) ‐> name="idxx"
3. name属性可以省略 但是要注意参数的位置
4. 如果非要把位置错开 可以使用 name 或者 index 或者 type
5. index 是下标 从0开始
6. type 在位置错开情况下只能在类型不一样的时候指定才有明显效果
-->
<bean id="user" class="com.zhl.entity.User">
<constructor-arg name="id" value="1"></constructor-arg>
<constructor-arg name="username" value="一右四分之一"></constructor-arg>
<constructor-arg name="realname" value="也是一右四分之一"></constructor-arg>
</bean>
复制代码
public class User {
private Integer id;
private String username;
private String realname;
public User() {
System.out.println("创建了一个对象");
}
public User(Integer id,String username,String realname) {
this.id = id;
this.username = username;
this.realname = realname;
}
}
复制代码
3.2 依赖和配置的细节
a、直接值(基本类型、String 等)
b、对其他bean的引用
c、内部bean
d、集合
e、null和空的字符串值
f、使用P命名标签简化基于 setter 属性注入XML 的配置
g、使用C命名空间,简化基于 构造函数的 xml
<bean id="user" class="com.zhl.entity.User">
<!--直接值(基本类型、String 等)-->
<property name="id" value="1"></property>
<!--设置null-->
<property name="username">
<null></null>
</property>
<property name="realname" value=""></property>
<!--对其他bean的引用 引用外部Bean
<property name="role" ref="role"></property>
-->
<!--使用内部bean 依赖注入其他bean-->
<property name="role">
<bean class="com.zhl.entity.Role">
<property name="roleId" value="1"></property>
<property name="roleName" value="管理员"></property>
</bean>
</property>
<!--list 注入:
如果泛型是基本数据类型<value>
如果泛型是bean <bean>-->
<property name="hobbies">
<list>
<value>唱歌</value>
<value>跳舞</value>
</list>
</property>
<!--map 注入
如果value是基本数据类型<entry key="1" value="Java"></entry>
如果value是bean value-ref-->
<property name="course">
<map>
<entry key="1" value="Java"></entry>
<entry key="2" value="数据库"></entry>
</map>
</property>
</bean>
<bean id="role" class="com.zhl.entity.Role"></bean>
<!--使用p命名空间简化基于setter属性注入XML配置
p:按Alt+Enter 自动加上命名空间
设置基本数据类型 或者p:wife-ref 引用外部bean
如果有集合类型 就不支持, 需要额外配置 <property>
-->
<bean id="user2" class="com.zhl.entity.User" p:id="1" p:username="一右四分之一" p:realname="一右四分之一" p:role-ref="role2">
<property name="hobbies">
<list>
<value>唱歌</value>
<value>跳舞</value>
</list>
</property>
</bean>
<!--使用c命名空间简化基于构造函数的XML 这种方式,类中必须自定义构造方法-->
<bean id="role2" class="com.zhl.entity.Role" c:roleId="1" c:roleName="管理员"></bean>
复制代码
3.3 使用 depends-on 属性
<!--使用depends‐on可以设置先加载的Bean 也就是控制bean的加载顺序-->
<bean class="com.zhl.entity.User" id="user" depends-on="role"></bean>
<bean id="role" class="com.zhl.entity.Role"></bean>
复制代码
3.4 懒加载 bean
<!--使用lazy‐init设置懒加载
默认为false: 在spring容器创建的时候加载(实例化)
true: 在使用的时候(getBean)才会去加载(实例化)
-->
<bean id="user" class="com.zhl.entity.User" lazy-init="false">
<property name="id" value="1"></property>
<property name="username" value="一右四分之一"></property>
<property name="realname" value="一右四分之一"></property>
</bean>
复制代码
3.5 自动注入
当一个对象中需要引用另外一个对象的时候,在之前的配置中我们都是通过 property标签来进行手动配置的,其实在spring中还提供了一个非常强大的功能就是自 动装配,可以按照我们指定的规则进行 配置,配置的方式有以下几种:
default/no:不自动装配
byName:按照名字进行装配,以属性名作为id去容器中查找组件,进行赋 值,如果找不到则装配null;
byType:按照类型进行装配,以属性的类型作为查找依据去容器中找到这个组件,如果有多个类型相同的bean对象,那么会报异常,如果找不到则装配null;
constructor:按照构造器进行装配,先按照有参构造器参数的类型进行装配,没有就直接装配null;如果按照类型找到了多个,那么就使用参数名作为id继续匹 配,找到就装配,找不到就装配null;
通过将autowire-candidate 属性设置为false,避免对bean定义进行自动装配;
通过将其元素的primary属性设置为 true,将单个bean定义指定为主 要候选项。
<!-- 自动注入
byType 根据类型去自动匹配 当出现多个类型或者匹配到类型则会报错(spring会根据bean里面的所有对象属性的类型,只要它匹配到bean里面某一个类型跟属性类型吻合就会自动注入)
byName 根据set方法的名字去自动匹配 (spring会根据bean里面的所有对象属性的set的名字,只要它匹配到bean里面某一个名字跟属性名字吻合就会自动注入)
constructor 根据构造器去匹配
优先会根据参数名字去匹配,假如参数名字没有匹配到,会根据参数类型去匹配
会根据构造函数的参数进行完整的匹配注入: 如果构造函数的参数Person(Wife wife3,User user) ioc容器里面必须要有同时有wife和user
名字没有匹配到会根据类型匹配 类型假如出现多个会注入失败但是不会报错
当根据类型匹配到多个 可以使用 1.设置某个bean为主要bean primary="true"
2.设置不需要自动注入的bean autowire-candidate="false" 忽略自动注入
-->
<bean id="user" class="com.zhl.entity.User" autowire="byType">
<property name="id" value="1"></property>
<property name="username" value="一右四分之一"></property>
<property name="realname" value="一右四分之一"></property>
</bean>
<!--autowire-candidate="false" 忽略自动注入
primary="true" 设置该bean为主要Bean(自动注入的时候,注入的是配置了 primary="true" 的Bean)-->
<bean class="com.zhl.entity.Role" id="role1" p:roleId="1" p:roleName="管理员" primary="true"></bean>
复制代码
public class IocTest {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring-ioc.xml");
User user = (User) context.getBean("user",User.class);
System.out.println(user.toString());//User{id=1, username='一右四分之一', realname='一右四分之一', role=com.zhl.entity.Role@727803de}
}
}
复制代码
4、Bean 的作用域
4.1、Singleton(单例)的作用域
4.2、Prototype(原型)的作用域
<!--作用域scope
singleton 默认:单例 只会在Ioc容器种创建一次
prototype 多例(原型bean) 每次获取都会new一次新的bean
-->
<bean id="user" class="com.zhl.entity.User" scope="singleton">
<property name="id" value="1"></property>
<property name="username" value="一右四分之一"></property>
<property name="realname" value="一右四分之一"></property>
</bean>
复制代码
5、自定义Bean的特性
5.1、生命周期回调
a、初始化方法回调
b、销毁方法回调
c、在非web应用中关闭Spring Ioc容器
/**
* 生命周期回调
* 1. 使用接口的方式实现:
* 1.初始化回调 实现InitializingBean 重写afterPropertiesSet 初始化会自动调用的方法
* 2.销毁回调 实现DisposableBean 重写destroy 销毁的时候会自动调用的方法
* 3.什么时候销毁?
* 在spring容器关闭的时候,或者使用 ConfigurableApplicationContext.registerShutdownHook 优雅地关闭
* 2. 基于配置的方式实现
*/
public class User implements InitializingBean, DisposableBean {
private Integer id;
private String username;
private String realname;
private Role role;
private List<String> hobbies;
private Map<Integer,String> course;;
public User() {
System.out.println("创建了一个对象");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("实例化User");
}
@Override
public void destroy() throws Exception {
System.out.println("销毁User");
}
}
复制代码
<bean class="com.zhl.entity.User" id="user" init-method="afterPropertiesSet" destroy-method="destroy"></bean>
复制代码
6、Bean定义的继承
<!--bean的继承 一个bean继承另一个bean
可以使用parent属性指定父类bean
如果想让父类bean不能被实例化 abstract="true"-->
<bean class="com.zhl.entity.User" id="user" abstract="true">
<property name="id" value="1"></property>
<property name="username" value="一右四分之一"></property>
<property name="realname" value="一右四分之一"></property>
</bean>
<bean class="com.zhl.entity.User" id="user2" parent="user" >
<property name="realname" value="一右四分之一2世"></property>
</bean>
复制代码
public class IocTest {
@Test
public void test(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-ioc.xml");
User user = (User) context.getBean("user2",User.class);
System.out.println(user.toString());//User{id=1, username='一右四分之一', realname='一右四分之一2世', role=null}
}
}
复制代码
近期评论