紧接着上次的内容我们继续来介绍IoC和DI,这里使用基于xml配置文件的方式,后面才使用注解和java代码。当然前面介绍过一个注解@Autowire可能还会使用到。
前面我们已经知道了BeanFactory是Spring最底层的接口,只提供IoC功能也就是负责创建,组装,管理bean,在应用中我们一般不使用BeanFactory,而是使用ApplicationContext。 ApplicationContext接口继承了BeanFactory,还提供了AOP集成(后面介绍),国际化,事件传播等功能。下面一起来介绍ApplicationContext
新建一个Cat类
package cn.hzu.ioc; public class Cat { public Cat() { System.out.println("创建了一只猫"); } }同样的配置文件要写好
<?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 id="cat" class="cn.hzu.ioc.Cat"></bean> </beans>创建测试类
package cn.hzu.ioc; import org.junit.jupiter.api.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.ApplicationContext; public class IoCTest { @Test void testApplicationContext() throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("/cn/hzu/ioc/IoCTest-context.xml"); Cat cat = ctx.getBean("cat", Cat.class); System.out.println(cat); } }大家可以发现使用ApplicationContext的方式比较简单,我们以后就使用这一种方式。下面我们来介绍一下ApplicationContext和BeanFactory的一点不同之处。
还是上面的Cat类,我们使用BeanFactory和ApplicationContext两种方式来进行测试
package cn.hzu.ioc; import org.junit.jupiter.api.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.context.ApplicationContext; public class IoCTest { // @Test // void testApplicationContext() throws Exception { // ApplicationContext ctx = new ClassPathXmlApplicationContext("/cn/hzu/ioc/IoCTest-context.xml"); // Cat cat = ctx.getBean("cat", Cat.class); // System.out.println(cat); // } @Test void testBeanFactory() throws Exception { Resource resource = new ClassPathResource("/cn/hzu/ioc/IoCTest-context.xml"); BeanFactory factory = new XmlBeanFactory(resource); System.out.println("----------------------------------------"); Cat cat = factory.getBean("cat", Cat.class); System.out.println(cat); } @Test void testApplicationContext() throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("/cn/hzu/ioc/IoCTest-context.xml"); System.out.println("----------------------------------------"); Cat cat = ctx.getBean("cat", Cat.class); System.out.println(cat); } }通过测试可以发现BeanFactory的测试结果为
---------------------------------------- 创建了一只猫 cn.hzu.ioc.Cat@d6da883
而ApplicationContext的测试结果为
创建了一只猫 ---------------------------------------- cn.hzu.ioc.Cat@6a01e23
通过观察测试结果我们可以得出结论
结论:BeanFactory有延迟初始化(懒:lazy)的特点,在创建Spring容器的时候,不会立马去创建容器中管理的Bean对象,而是要等到从容器中去获取对象的时候,才去创建对象.。ApplicationContex的方式t在创建Spring容器的时候,就会把容器中管理的bean立马初始化,而不会等到获取bean的时候才去初始化.
当然我们可以自己手动配置延迟初始化 配置某个bean
<bean id="cat" class="cn.hzu.ioc.Cat" lazy-init="true"/>配置所有bean
<?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" default-lazy-init="true"> </beans>这里我们使用JUnit5的测试方式,配置文件的命名和存放位置我上次介绍过了,不知道的话我最后会把项目结构贴出来。测试结果我就不截图了,都是创建了一个bean对象,只是方式不同
(无参数构造器),最标准使用最多,我们前面已经用过
package bean_constuctor; public class Cat { public Cat() { System.out.println("创建了一只猫"); } }配置文件
<?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 id="cat1" class="bean_constuctor.Cat" /> </beans>测试类
package bean_constuctor; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; @SpringJUnitConfig public class App { @Autowired private Cat c1; @Test void test() throws Exception { System.out.println(c1); } }@Autowired注解上次有介绍过,不懂的话后面会详细讲
配置文件
<?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"> <!-- 静态工厂方法实例化 class的属性值为静态工厂类,factory-method的属性值为创建对象的工厂方法--> <bean id="cat" class="bean_static_factory.CatFactory" factory-method="createInstance" /> </beans>测试类
package bean_static_factory; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; @SpringJUnitConfig public class App { @Autowired private Cat c1; @Test void test() throws Exception { System.out.println(c1); } }类还是跟上面的差不多,注意跟静态工厂方法比较
package bean_instance_factory; public class Cat { } package bean_instance_factory; public class CatFactory { public Cat createInstance() { Cat c = new Cat(); return c; } }配置文件
<?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 id="catFactory" class="bean_instance_factory.CatFactory"/> <bean id="cat" factory-bean="catFactory" factory-method="createInstance"/> </beans>测试类
package bean_instance_factory; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; @SpringJUnitConfig public class App { @Autowired private Cat c1; @Test void test() throws Exception { System.out.println(c1); } }配置文件
<?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"> <!-- 实现FactoryBean接口实例化--> <bean id="cat" class="bean_factory_bean.CatFactory"> </bean> </beans>测试类
package bean_factory_bean; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; @SpringJUnitConfig public class App { @Autowired private Cat c1; @Test void test() throws Exception { System.out.println(c1); } }在Spring容器中Bean的作用域是指其创建的Bean对象相对于其他Bean对象的请求可见范围,语法格式如下
<bean id="" class="" scope="作用域"/>singleton单例:在SpringIoC容器中仅存在一个Bean实例(默认) prototype多例:每次从容器中调用Bean是,都返回一个实例,即每次调用getBean()时,相当于执行new XXXBean(),但是不会在启动容器时创建对象(也就是说,只要指定了多例,无论是以BeanFactory还是ApplicationContext获取的Bean对象都是延迟初始化的,上面已经讲过延迟初始化了) request session globalSession application web-aware websocket 这几个就不介绍了用到时再说,在开发中主要使用singleton单例和prototype多例 使用多例的话不会自动创建对象,也就是说在调用的时候才会去创建,此时ApplicationContext和beanFactory都是延迟初始化的 下面我们还是用上面的Cat类来证明单例和多例确实存在 Cat类
package scope; public class Cat { public Cat() { System.out.println("创建了一只猫"); } }配置文件(先使用默认的单例)
<?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 id="cat" class="scope.Cat" scope="singleton"/> </beans>测试类(创建多个Cat对象,看看是不是同个对象)
package scope; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; @SpringJUnitConfig public class App { @Autowired private Cat Cat1; @Autowired private Cat Cat2; @Autowired private Cat Cat3; @Test void test() throws Exception { System.out.println(Cat1); System.out.println(Cat2); System.out.println(Cat3); } }测试结果 我们可以看到三个对象都是同一个对象。 接下来我们仅改变配置文件,将单例变成多例再测试一次
配置文件
<?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 id="cat" class="scope.Cat" scope="prototype"/> </beans>测试结果 可以发现三个对象不是同一个对象。
我先把代码贴一下再来解释(还是使用上面的Cat类,不过要做些修改) Cat类
package bean_life; public class Cat { //创建对象 public Cat() { System.out.println("创建了一只猫"); } //对象初始化 public void init() { System.out.println("创建对象之前初始化"); } //对象主要功能 public void doWork() { System.out.println("猫工作了,老鼠快跑"); } //对象销毁执行的 public void end() { System.out.println("工作结束......"); } }配置文件
<?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"> <!-- init-method: 定义初始化方法,在构造器执行之后,立马执行 destroy-method:定义销毁之前的方法,在销毁执行之前,调用 --> <bean id="cat" class="bean_life.Cat" init-method="init" destroy-method="end"/> </beans>测试类
package bean_life; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; @SpringJUnitConfig public class App { @Autowired private Cat cat; @Test void testIoC() throws Exception { cat.doWork(); } }测试结果 通过测试结果和查看代码我们可以知道SpringIoC容器可以负责帮我们创建对象并做对象初始化和销毁之前的扫尾操作,也就是SpringIoC容器可以帮我们管理Bean对象,这一点体现得淋漓精致了吧。谈一下配置文件代码中的两个属性 init-method:Bean生命周期初始化方法,对象创建后就进行调用 destory-method:容器被正常关闭的时候,如果Bean被容器管理,就会调用该方法 语法格式:
<bean id="" class="" init-method="该类中初始化方法名" destroy-method="该类中销毁方法名"/>值得一提的是:销毁方法必须是SpringIoC容器关闭前才会执行,若是采用普通的测试,则需要自己手动关闭SpringIoC容器,不然容器不会自动关闭,销毁方法也不会执行,下面来看一下普通测试类。其他都不改动,就新写一个测试类 测试类
package bean_life; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestLife { @Test void test() throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext( "bean_life/App-context.xml"); Cat ds = ctx.getBean("cat", Cat.class); ds.doWork(); //不会自动释放资源 // ctx.close(); } }测试结果 可以看到销毁方法不会执行,需要手动调用ApplicationContext的close方法才会关闭Spring容器,close方法来自AbstractApplicationContext ,被ApplicationContext继承了。
**注意:**关闭SpringIoC容器的最好方法并不是调用close()方法,而是把Spring线程作为JVM的子线程使用registerShutdownHook()方法进行关闭。
好了IoC这一部分就介绍到这里,有什么错误的地方还望各位指正,下节我们介绍DI和Bean的继承。
好好学习,天天向上,每天进步一点点,为我自己加油!!!!