1.创建Student类
2.创建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-4.3.xsd">
<bean id="stu" class="com.bean.Student">//从容器中取Student对象就是通过id取
</bean>
</beans>
3.编写测试类
@Test
public void create() {
String path="com/ioc/set_1/set.xml";
ApplicationContext ioc = new ClassPathXmlApplicationContext(path);//获取IOC容器
Student stu = (Student)ioc.getBean("stu");//从容器中取出对象
System.out.println(stu);
}
这就是简单的IOC容器的使用方法了,那么一些特殊情况应该怎么处理呢?
一、为对象注入属性
<bean id="stu2" class="com.bean.Student">
<property name="id" value="10"></property>
<property name="name" value="tom"></property>
<property name="age" value="11"></property>
</bean>
使用property标签,name是属性名,value就是属性值。那如果属性值是对象怎么办呢?
<bean id="tea" class="com.bean.Teacher">
<property name="id" value="11"></property>
<property name="name" value="jack"></property>
<property name="student" ref="stu2"></property>
</bean>
如果属性值是对象,id不变,依然为属性名,value改成ref,ref里面的值填写为对应对象在ioc容器里面的id。
二、向对象注入集合
前面解决了基本数据类型,字符串,自定义对象的属性赋值,那么如果是list,set,map集合和Properties应该怎么注入呢。
如果是基本数据类型
<bean id="stu" class="com.bean.Student">
<property name="name" value="tom"></property>
<property name="list">//list集合
<list value-type="">//value-type中可以指定泛型的类型,如果不需要就不用写value-type
<value>10</value>
<value>tom</value>
</list>
</property>
<property name="set">//set集合
<set>
<value>123</value>
<value>tom</value>
</set>
</property>
<property name="map">//map集合
<map>
<entry key="name" value="tom"></entry>
<entry key="age" value="1"></entry>
<entry key="gender" value="男"></entry>
</map>
</property>
<property name="prop">//properties
<props>
<prop key="tom">123</prop>
<prop key="age">111</prop>
<prop key="gender">男</prop>
</props>
</property>
</bean>
如果list和set集合中的是引用数据类型,只需要把value标签换成ref标签即可,如果map集合中的key和value为对象,那么key和value可以换成key-ref和value-ref。
三、使用构造器注入数据
前面我们都是利用set方法注入的值,那么是否可以使用构造器注入值呢?当然可以
<bean id="stu" class="com.bean.Student">
<constructor-arg index="0" type="long" value="22"></constructor-arg>
<constructor-arg index="1" type="java.lang.String" value="tom"></constructor-arg>
</bean>
index代表的是构造器中属性的下标,这里我们调用的是new Student(long id,String name)的构造器,index="0"代表是id属性,type代表属性的类型,value就是属性的值,同样如果属性的值是对象,那么value改成ref即可,ref中填写bean对象的id。
四、自动注入
每次写一个bean对象,如果对象里面还有一个对象属性,都要写一遍,这样就太麻烦了,有没有什么简单的方法呢?有,这就是自动注入,从当前ioc容器获得一个对象,注入到当前ioc容器的另一个bean对象中。
<bean id="student" class="com.bean.Student">
<property name="id" value="1"></property>
<property name="name" value="jack"></property>
<property name="prop">
<props>
<prop key="tom">123</prop>
</props>
</property>
</bean>
<bean id="tea" class="com.bean.Teacher" autowire="byName">
<property name="name" value="老师"></property>
</bean>
当前Teacher类中有Student类型的属性,使用autowire,就可以把当前ioc容器中的Student类型的属性注入到Teacher对象中
注意:byName和byType区别,byName主要是根据ioc中对象的id和Teacher中Student类的属性名来查找,找到一致的就注入,byType是查找ioc中类型和Teacher中Student类一致的,一致的就注入。
五、容器中对象的生命周期
单例对象
1.创建
在容器创建的时候就创建了所有的对象(单例)
可以修改为非单例(bean scope = “prototype”)
2.初始化
创建完成立刻初始化 bean标签中可以写init-method=‘方法名’,此时会立刻执行这个初始化方法
3.执行
从容器中获取出来就执行
4.销毁
当容器销毁的时候就销毁,如何销毁容器呢?
ioc.destroy();
容器中的所有单例对象都会被销毁
非单例对象
1.创建
获取的时候创建,创建完立刻初始化并且执行
2.销毁
容器不管理
六、使用多个xml文件创建容器
String[] path ={"xxx.xml","xxxx.xml"};
ApplicationContext ioc = new ClassPathXmlApplicationContext(path);
xml文件中的对象可以互相引用。
但是一般我们不推荐这么做,因为后期如果要加xml文件要重新动java文件,我们一般在xml文件中使用import标签引入其他xml文件
七、工厂
创建一个LT类,实现序列化接口
public class LT implements Serializable{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
创建一个LTFactory类,实现FactoryBean接口,实现里面的方法
public class LTFactory implements FactoryBean<LT>{
@Override
public LT getObject() throws Exception {
return new LT();
}
@Override
public Class<?> getObjectType() {
return LT.class;
}
@Override
public boolean isSingleton() {
return false;
}
}
在xml文件中注入LTFactory,此时创建ioc容器,从ioc容器中获取的是LT对象,而非LTFactory对象。
如果不通过实现接口的方式,来定义这么一个工厂类,应该怎么做呢?
比如我这个类,返回的是一个LT对象
public class LGM {
public LT getLT(){
return new LT();
}
}
那么在xml文件中要这么配置,第一个配置LGM,但是只这样调用容器返回的还是LGM对象,而不是LT对象,我们需要让spring知道这是一个工厂类对象,就需要用factory-bean指定工厂对象在ioc容器中的id,factory-method指定工厂类对象生成LT的方法。一个工厂对象可以创造多个对象,只需要多个配置即可。
<bean id="lgm" class="com.ioc.instanceFactory_9.LGM"></bean>
<bean id="foc" factory-bean="lgm" factory-method="getLT"></bean>
八、静态工厂
因为静态方法只需要类就能调用,所以和上面的相比只需要一个bean标签,因为本身就是一个工厂,所以不需要factory-bean
<bean id="foc" class="com.ioc.staticFactory_10.XM" factory-method="getLT"></bean>
九、发布事件
定义一个类继承ApplicationEvent类
public class Myevent extends ApplicationEvent{
public Myevent(Object source) {
super(source);
// TODO Auto-generated constructor stub
}
}
定义一个Listener实现ApplicationListener接口,
监听ioc容器中的事件
public class MyListener implements ApplicationListener<Myevent>{//泛型是要监听的事件
@Override
public void onApplicationEvent(Myevent arg0) {
// TODO Auto-generated method stub
System.out.println("11");
}
}
在xml文件中配置监听器
<bean class="com.ioc.event_12.MyListener"></bean>
十、注解!!!十分重要
如何使用注解进行配置
@Component:写在类名上,把类对象放到ioc容器中,相当于bean标签
@Autowired:写在属性上,构造器上,set方法上,从当前容器获取对象注入进来。(寻找方式:先使用byType,找到多个再byName)
在xml文件中配置注解所在的包,读取注解
<context:annotation-config></context:annotation-config>
<context:component-scan base-package="com.ioc.annotation_13"></context:component-scan>
但是这种方式还是要在xml文件中配置,可以不用吗?当然可以~
我们之前都是使用ApplicationContext ioc = new ClassPathXmlApplicationContext(path);
的形式创建容器,换成使用AnnotationConfigApplicationContext创建ioc容器
创建一个JavaConfig类
@Configuration//这个注解表面这是一个配置类
@ComponentScan("com.ioc.annotation_13")//扫描这个包下的注解
public class MyConfig {
}
测试类
@Test
public void test() {
AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(MyConfig.class);
System.out.println(ioc.getBean("boss"));
}
这时候就不需要xml文件了