第4章 IoC容器
1、IoC(控制反转)是Spring容器的核心,AOP、声明式事务等都基于IoC。 2、IoC:某一接口的实现类不由调用类来决定,而是交给第三方来决定。控制权翻转到第三方。 3、由于IoC这个词不够见名知意,后来软件界泰斗级别的人物Martin Fowler提出了ID(依赖注入)来代替。 4、IoC类型: IoC可以划分为三种:构造函数注入、属性注入、接口注入。Spring支持构造函数注入和属性注入。 构造函数注入: 将接口实现类通过调用类的构造函数的参数传入到调用类中。(调用类不用关心谁才是实现类,只需要关心实现类会在构造函数中传入) 属性注入: 由于实现类不一定就必须在初始化是出现。因此可以使用属性注入。即通过属性的SetXxx方法注入到类中。 接口注入: 将调用方法中所有解决依赖的方法抽取到一个接口中。然后调用方法实现这个接口即可。 5、通过容器完成依赖关系的注入 程序的依赖关系交给容器完成,程序开发人员专注于开发更有意义的业务逻辑。这是我们期望的。 Spring容器,通过使用java或者xml文件来描述依赖关系,并自动完成初始化和依赖注入的工作。 下面是演员饰演角色的案例: <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans"> xmlns:xsi="http://www.w4.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id = "geli" class = "xxx.yyy.刘德华"> <bean id = "moAttack" class = "com.smart.ioc.MoAttack" p:geli-ref="geli" /> <!--通过geli-ref建立依赖关系--> </beans> 使用 new XmlBeanFactory("beans.xml")等方法即可启动容器。容器启动后根据描述信息自动实例化Bean并完成依赖关系的装配。这个神奇的功能是通过java反射实现的。 6、类装载的工作机制 类装载器通过字节码文件在jvm中创建表示类的组件。类装载器将类装入jvm中需要以下几个步骤。 1:装载:查找和导入Class文件 2:链接:执行校验(校验文件的真确性)、准备(给静态成员分配空间)和解析(将符号引用转换为直接引用)等。 3:初始化:对类的静态变量,静态代码块进行初始化工作。 7、资源抽象接口 Spring提供了一个Resource的接口,为应用提供了更强的底层资源访问能力,拥有对不同资源的访问能力,在Spring中它起到了很大作用(加载各种资源)。 Resource的主要方法: Boolean exists(): 资源是否存在 Boolean isOpen(): 资源手否打开 URL getURL() throws IOException: 如果底层资源可以表示成URL,那么返回URL。 File getFile() throws IOException: 如果底层资源对应于一个File,返回对应的File对象。 8、BeanFactory和ApplicationContext BeanFactory是Spring最为核心的接口。ApplicationContext建立在BeanFactory之上,提供了更多面向应用的功能。 BeanFactory我们一般称为IoC容器,ApplicationContext称之为上下文。为了方便有时候也将ApplicationContext称之为容器。 BeanFactory: Spring框架的基础设施,面向Spring本身。 ApplicationContext: 面向Spring框架的使用者,几乎所有的应用场合都使用ApplicationContext而不使用BeanFactory。 9、BeanFactory: 正如其名,BeanFactory是一个工厂,但是和传统的工厂有所不同,它可以创建和管理各种java对象。Spring将这些对象称之为Bean。 但是javaBean是一个规范(有无参构造、不依赖特定容器等。)但是SpringBean比较宽泛,被容器管理的都叫做Bean。 Spring为BeanFactory提供了多种实现。目前建议使用的是:XmlBeanDefinitionReader和DefaultListableBeanFactory。 通过BeanFactory的继承体系可以清晰的看出BeanFactory提供了那些功能。 初始化BeanFactory 下面使用Spring配置文件描述Car,然后使用BeanFactory装载配置文件。启动SpringIoC容器。 beans.xml配置文件 <bean id = "car1" class = "com.smart.Car"> p:brand="红旗" p:color="黑色" p:maxSpeed="200" </bean> 下面通过XMLBeanDefinitionReader和DefaultListableBeanFactory实现启动SpringIoC容器。 public class BeanFactoryTest{ @Test public void getBean() throws Throwable{ ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource res = resolver.getResource("classpath:com/smart/beanFactory/beans.xml"); //获取配置文件资源 System.out.println(res.getURL()); DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); XMLBeanDefinitionReader reader = new XMLBeanDefinitionReader(factory); reader.loadBeanDefinitions(res); //XMLBeanDefinitionReader通过Resource装载配置信息、启动IoC容器。 //启动IoC容器后并不会立刻实例化bean,而是在使用时才创建。 //对于单例的Bean来说,bean会被缓存起来,下次使用直接调用。 Car car = factory.getBean("car" , Car.class); car.introduce(); } } 10、ApplicationContext介绍 ApplicationContext是在BeanFactory的基础上派生出来的。实现了很多功能。 ApplicationContext的主要实现类是:ClassPathXMLApplicationContext(默认从类路径加载配置文件)和FileSystemXMLPathApplicationContext(默认从文件系统中加载配置) 从ApplicationContext的继承体系可以看到,它继承了BeanFactory的实现类并扩展了其功能。 ConfigurableApplicationContext扩展了ApplicationContext它结合了生命周期类,让ApplicationContext具有了如下方法 refresh(),close()让ApplicationContext具有了启动、刷新、关闭的能力。 在上下文关闭的情况下使用refresh()可启动上下文 在启动上下文的情况下使用refresh()可清除缓存并重写转载配置信息。 调用close()方法会关闭上下文。 初始化ApplicationContext 如果配置文件在类路径下:可以使用ClassPathCmlApplicationContext实现类 ApplicationContext ctx = new ClassPathCmlApplicationContext("com/smart/context/beans.xml"); //对于ClassPathCmlApplicationContext来说"com/smart/context/beans.xml"等同于:"classpath:com/smart/context/beans.xml" 如果配置文件放在文件系统下可以优先考虑:FileSystemXmlApplicationContext类 ApplicationContext ctx = new FileSystemXmlApplicationContext("com/smart/context/beans.xml") //对于FileSystemXmlApplicationContext来说"com/smart/context/beans.xml"等同于:"file:com/smart/context/beans.xml" 如果要指定一组配置文件可以使用以下形式: new new FileSystemXmlApplicationContext(new String[]{"com/smart/context/beans.xml","config.xml","config2.xml"}) 11、javaConfig Spring提供了使用java配置Bean的方法 可以使用@Configuration注解标识一个POJO类为Spring提供Bean的描述。 例如: @Configuration public class Beans{ @Bean{name = "car"} public Car buildCar(){ Car car = new Car(); 这种方法容易控制初始化过程。 car.xxx();car.yyy(); return car; } } Spring为基于注解的配置类提供了专门的ApplicationContext:AnnotationConfigApplicationContext。 启动容器: public class AnnotationApplicationContextTest{ @Test public void getBean(){ //通过一个javaConfig类创建上下文 ApplicationContext ctx = new AnnotationConfigApplicationContext(Beans.class); //获取Bean Car car = new Car("car" , Car.class); } } 12、Spring4.0还支持Groovy DSL 进行Bean定义的配置。使用Groovy容易实现比较复杂的Bean初始化配置。 13、WebApplicationContext类体系结构 WebApplicationContext是Spring专门为Web准备的上下文。它允许从web根路径中装配文件完成初始化。 为了使web中的servletContext对象可以使用Spring的上下文,WebApplication作为属性在ServletContext中。 Spring专门提供了一个WebApplicationUtils的类,使用该类的getWebApplicationContext(ServletContext sc)方法可以从ServletContext中取到WebApplicationContext WebApplicationContext也可以返回ServletContext的引用。从而实现web应用上下文和web容器的互相访问。 14、ConfigurableWebApplicationContext ConfigurableWebApplicationContext扩展了WebApplicationContext。允许通过配置的方式实例化WebApplicationContext。同时提供了两个有用的方法: 1:setServletContext(ServletContext servletContext) 为Spring设置web上下文,以便二者结合。 2:setConfigLocations(String[] configLocations) 设置Spring配置文件地址,一般情况下Spring配置文件地址是相对于Web根目录的地址。例如:“/WEB-INF/smart-service.xml” 但使用setConfigLocation也可以指定资源类型前缀,如:"classpath:smart-service.xml" 15、WebApplicationContext初始化 由于WebApplicationContext的创建需要ServletContext实例。所以和ApplicationContext和BeanFactory有所区别。 可以通过在web.xml中配置自启动的servlet或者定义Web容器监听器。 下面是Spring提供的用于启动WebApplicationContext的Servlet和Web容器监听器,实现二者其一,并在web.xml中配置即可。 1:org.springframework.web.context.ContextLoaderListener。 下面是使用ContextLoaderListener启动WebApplicationContext的配置 <!--指定配置文件--> <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/smart-dao.xml,/WEB-INF/smart-service.xml </param-value> </context-param> <!--声明Web容器监听器--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> 2:org.springframework.web.context.ContextLoaderServlet。 如果web容器不支持容器监听器(一些第版本的web容器就不支持)。可以使用ContextLoaderServlet <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/smart-dao.xml,/WEB-INF/smart-service.xml</param-value> </context-param> <!--声明自动servlet--> <servlet> <servlet-name>springContextLoaderServlet</servlet-name> <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class> <!--启动顺序--> <load-on-startup>1</load-on-startup> </servlet> 由于WebApplicationContext需要使用日志,可以将log4J的配置文件放在WEB-INF/classes下,这样log4J就可以顺利启动了。 如果log4J的配置文件放在了别的地方,需要用户在web.xml中配置log4J的配置位置。Spring为Log4J提供了启动类。具体看书。 16、bean生命周期????????????