Spring框架系列 1 -- IOC和DI

Spring框架系列 1 -- IOC和DI


一、spring bean生命周期

spring的生命周期为:实例化前奏-->实例化-->实例化后期-->初始化前期-->初始化-->初始化后期-->bean的具体调用-->销毁前-->销毁。

Spring框架系列 1 -- IOC和DI_第1张图片


1-2:创建实例;

   现在假设spring就是个容器,而配置文件中配置的bean属性才是我们真正需要的东西。

      创建实例就是说,我把配置文件中的bean信息取出来化作一个真正的bean(实例化)并放到容器中。

      InstantiationAwareBeanPostProcessor是实例化前后做的事情。

3-4:注入依赖关系;

  第3步是创建实例之后对实例作了一些处理,第4步是把xml中配置的bean属性值赋予给容器中的实例化之后的bean。

5:bean初始化之前的处理;

      BeanPostProcessor是初始化前后做的事情

  应用开发者需要把容器中实例化的bean拿出来用,这个拿出来的过程就是初始化(注意实例化与初始化的区别,instantiation (实例化)和initialization(初始化)),第五步就是在初始化之前,对已经实例化的bean再作一定的处理。

6,7:初始化。

  如果bean实现了InitializingBean,那么将调用InitializingBean的afterPropertiesSet()方法做一些初始化处理。

      如果没有实现InitializingBean,而是在配置文件中定义了init-method属性值,那么系统会找到init-method对应的方法并执行之,程序猿哥哥一般在这个方法里写一些初始化操作;

8:bean初始化之后的处理。

  初始化之后在这个方法中再对bean进行修饰装点。

9,10:交给应用开发人员处理;

  如果在中指定Bean的作用范围是scopt="prototype",那么系统将bean返回给调用者,spring就不管了(如果两个实例调用的话,每一次调用都要重新初始化,一个实例的修改不会影响另一个实例的值。如果指定Bean的作用范围是scope="singleton",则把bean放到缓冲池中,并将bean的引用返回给调用者。这个时候,如果两个实例调用的话,因为它们用的是同一个引用,任何一方的修改都会影响到另一方。)

11.bean用完之后;

  对于scope="singleton"的bean,使用完之后spring容器会做一些处理,比如编写释放资源、记录日志等操作。

12.销毁;

  调用配置文件中的销毁方法销毁实例。

二、Spring基于Schema的Xml配置方案

XML Schema : 用来描述 XML文档的结构,也被简称为XSD(XML Schema Definition),是一些规则的集合。(方式:通过定义schema文件 如 spring-tx-3.0.xsd)

xmlns : 命名空间是W3C推荐标准提供的一种统一命名XML文档中的元素和属性的机制

.xsd文件 : 用XML w3c 标准命名空间中规定的元素和属性编写的以targetNamespace作为{目标命名空间}的XML文件,能够约束引入此{目标命名空间}定义的元素和属性的XML文件。

.targetNamespace : 目标命名空间,它的主要作用是指明Schema定义的元素的命名空间。








	
	
		
			
				classpath:properties/druid.properties
				
			
		
	

	
	
	
	
	
	 
	
	                            		
	  
	
	
	
	
	
	
	
		
			
				
				
				
				
				
				
				
			
		
		
		
	
	
	
	
	
		
			
			
			
			
             
		
	
	
	
	
	
	
	
    
    
    

xmlns : 是spring的内置xsd                     xsi : 是调用xsi的schemaLocation去寻找具体的xsd位置
Spring除了基于XML的配置,还有基于Bean,基于注解的配置。但是基于XML的配置功能最强
三、IoC(控制反转)和DI(依赖注入)

IOC, spring的核心,贯穿Spring始终。直观的来说,就是由spring来负责控制对象的生命周期和对象间的关系,将对象之间的关系抽象出来,通过spring容器控制对象生成时机,减少对象之间的耦合度。

所谓控制反转,就是把原先我们代码里面需要实现的对象创建、依赖的代码,反转给容器来帮忙实现。那么必然的我们需要创建一个容器,同时需要一种描述来让容器知道需要创建的对象与对象的关系。这个描述最具体表现就是我们可配置的文件。

SpringIOC 的主要依赖源码是 spring-beans 和 spring-context两个包。

IOC容器指的是实现对依赖对象的创建(无参构造器)、管理(参数注入)、销毁(关闭BeanFactory).

spring的依赖注入有属性注入、构造函数注入、工厂方法注入等多种方式。Spring要把xml配置中bean的属性实例化为具体的bean,"依赖注入"是关卡。所谓的"依赖注入",就是把应用程序对bean的属性依赖都注入到spring容器中

首先是属性注入:

    
        
            host.com
        
 
  1. 配置文件中的lazy-init="default"或者="false",意思是,该bean在spring容器启动时就实例化。而lazy-init="true"表示该bean在spring容器启动时不会实例化,而在需要这个bean时才实例化。
  2. name与value分别对应什么,一目了然。
  3. name书写有一定的规范,比如你写个cARBrand可能会出问题。前两个字母,要么全部大写,要么全部小写。
  4. value中不能掺杂xml的特殊符号,如:& < > “ ‘ 如果必须要写这些字符,要用来转义。
  5. value里面如果要设置null值,不能什么都不写,要变为:
  6. 假如bean类是Icp,Icp类有一个属性是car,那么你想直接在Icp的配置文件中定义Car的brand属性,就酱紫:
  7. 如果是集合类型,配置里面要这样写:

    
        aili.com
        apple.com
        yun.qq.com
    

	
	    
	        BMW
	        BYD
	    
	

                7.HashMap


            
                
                    
                        Saturday
                    
                    约妹子
                
                
                    
                        Sunday
                    
                    发呆
                
            
        

            8.Properties 它是一种特殊的Map,键值都是String类型


            
                [email protected]
                [email protected]
            
        

构造函数注入: 构造函数的注入可以让属性在实例化的过程中就有了值(其实就相当于java在bean的构造函数中给属性赋值,只不过现在是在xml配置中实现)

    
        
            niaofuli.com
        
        
            20000
        
	 

工厂方法的注入:

工厂类负责创建一个或者多个bean实例,调用工厂方法即可获取该实例。一旦在XML中注册了某工厂,那么调用工厂的过程中已经把该Bean实例化了。

code


    
    
package com.test;

public class CarFactory {
   public Car createCar(){
       Car car = new Car();
       car.setBrand("红旗");
       return car;
   }

}

code 第6行的factory-bean指向第7行的id,第6行的factory-method就是Factory要调用的方法。第7行是Factory的Bean配置(也就是说,CarFactory这个java写的工厂类本身也是一个bean ).调用createCar就可以获取Car实例。

如果方法是静态的:



     
spring使用p命名空间进一步作了简化。
修改前

         
         
         
     
p命名


基于注解配置

基于XML的bean属性配置:bean的定义信息与bean的实现类是分离的。// 基于注解的配置:bean的定义信息是通过在bean实现类上标注注解实现。

1、Component : spring看到这个属性标志,会自动将FilterDao变成容器管理类,等同于在XML中这样配置:


package com.lh.json;

import org.springframework.stereotype.Component;

/**
 * 页面筛选字段内容
 * @author JOMNN
 *
 */
@Component
public class FilterDao {

	private String fvname;
	
	private int fv;

	public String getFvname() {
		return fvname;
	}

	public void setFvname(String fvname) {
		this.fvname = fvname;
	}

	public int getFv() {
		return fv;
	}

	public void setFv(int fv) {
		this.fv = fv;
	}

	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return this.fvname+"-"+this.fv;
	}
	
	
}

自动扫描注解的bean

默认的过滤器会去解析base-package下的含有@Component注解的类作为bean,其中@Repository, @Service, and @Controller都是@Component的子注解,故,默认的过滤器会将它们全部解析成bean

1、@Component 一般的bean类上面配置。

2、@Controller 对应表现层的Bean,也就是action。

3、@ Service 对应业务层bean。

4、@ Repository 对应持久层Bean。

5、@Autowired 成员变量或方法入参处标注,按类型匹配自动注入。

6、@Qualifier 按名称匹配方式注入。

7、@PostConstruct指定初始化方法。(相当于XML配置中的init-method)

8、@PreDestroy指定销毁方法。(相当于XML配置中的destroy-method)

9、@Scope 指定bean是prototype还是singleton。

使用context的规则:component-scan. 扫描这个包中的所有类,并从注解信息中获取bean的基本信息(没加注解的不扫描也不实例化)。


context:component-scan标签下面可以再加子标签过滤

	
	
	    
	    
		
		
		
		
	
    

附:过滤规则设置

context:component-scan节点允许有两个子节点。filter标签的type和表达式说明如下:

Filter Type Examples Expression Description include-filter为例
annotation org.example.SomeAnnotation 符合SomeAnnoation的target class

表示扫描base-package下的类上加了Aspect注解的类,并注册到spring的bean容器

assignable org.example.SomeClass 指定class或interface的全名

指定扫描StuService类作为bean

aspectj org.example..*Service+ AspectJ語法  
regex org\.example\.Default.* Regelar Expression  
custom org.example.MyTypeFilter Spring3新增自訂Type,實作org.springframework.core.type.TypeFilter  

package com.lh.controller;

import java.io.File;
import java.util.HashMap;
import java.util.UUID;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.annotations.Param;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import com.lh.def.SqlOpDef;
import com.lh.excel.util.ExcelUtil;
import com.lh.service.RequestAsyncProcessService;

/**
 * 数据库添加页面
 * @author JOMNN
 *
 */
@Controller
@RequestMapping(value="inster")
public class InsterController implements ApplicationEventPublisherAware{
	Log log=LogFactory.getLog(InsterController.class);
	/**
	 * 事件分发
	 */
	@Resource
	private ApplicationEventPublisher publisher;
	/**
	 * 请求队列
	 */
	@Resource
	private RequestAsyncProcessService requestAsyncProcessService;
	
	/**
	 * ICP库
	 * @return
	 */
	@RequestMapping(value="icp")
	public ModelAndView icpInsterHtml(){
		HashMap map = new HashMap();
		map.put("title_name", "添加: Icp备案库数据");
		map.put("page", "1");
		return new ModelAndView("html/inster",map);
	}
	
	/**
	 * 主域分类库
	 * @return
	 */
	@RequestMapping(value="hostType")
	public ModelAndView hostTypeInsterHtml(){
		HashMap map = new HashMap();
		map.put("title_name", "添加: 主域分类库数据");
		map.put("page", 2);
		return new ModelAndView("html/inster",map);
	}
	
	/**
	 * 主域白名单库
	 * @return
	 */
	@RequestMapping(value="hostWhite")
	public ModelAndView hostWhiteInsterHtml(){
		HashMap map = new HashMap();
		map.put("title_name", "添加: 主域白名单库数据");
		map.put("page", 3);
		return new ModelAndView("html/inster",map);
	}
	
	/**
	 * 域名状态库
	 * @return
	 */
	@RequestMapping(value="domainState")
	public ModelAndView domainStateInsterHtml(){
		HashMap map = new HashMap();
		map.put("title_name", "添加: 域名状态库数据");
		map.put("page", 4);
		return new ModelAndView("html/inster",map);
	}
	
	/**
	 * 域名页面优化库
	 * @return
	 */
	@RequestMapping(value="domainOptimize")
	public ModelAndView domainOptimizeInsterHtml(){
		HashMap map = new HashMap();
		map.put("title_name", "添加: 域名页面优化库数据");
		map.put("page", 5);
		return new ModelAndView("html/inster",map);
	}
	
	/**
	 * 主域白名单库
	 * @return
	 */
	@RequestMapping(value="domainInfo")
	public ModelAndView domainInfoInsterHtml(){
		HashMap map = new HashMap();
		map.put("title_name", "添加: 域名信息库数据");
		map.put("page", 6);
		return new ModelAndView("html/inster",map);
	}
	
	@RequestMapping(value="single",method=RequestMethod.POST)
	public String singleHtml(@Param("page") int page){
		if (page == 1) {
			return "html/instericp";
		}
		else if (page == 2) {
			return "html/insterhostType";
		}
		else if (page == 3) {
			return "html/insterhostWhite";
		}
		else if (page == 4) {
			return "html/insterdomainState";
		}
		else if (page == 5) {
			return "html/insterdomainOptimize";
		}
		else if (page == 6) {
			return "html/insterdomainInfo";
		}
		else {
			return "index/login";
		}
	}
	
	@RequestMapping(value="inster.do")
	@ResponseBody
	public String insert(HttpServletRequest request,@Param("file") MultipartFile file){
		
		//服务器上使用
        String rootPath =request.getServletContext().getRealPath(File.separator+"WEB-INF");//target的目录
        //使用sessionid + UUID 生成文件号
        String fileId = request.getSession().getId() + UUID.randomUUID().toString().replaceAll("-", "")+SqlOpDef.getInster();
        return ExcelUtil.analysisExcel(file, rootPath,publisher,requestAsyncProcessService,fileId,SqlOpDef.getInster());
	}
	
	@Override
	public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
		this.publisher = publisher;
	}
	
    @PostConstruct
    public void init(){
        log.info("本应用程序正式拉开帷幕。。。");
    }
    
    @PreDestroy
    public void destroy(){
        log.info("本应用程序正式落幕,吓吓侬。。。");
    }
}

spring看到@Controller会如同看到@Component一样,转换成spring容器管理的bean。

spring看到@Autowired(required=false) / @Resource会自动注入(实例化)下面的requestAsyncProcessService。(直接用就行,就不用你来new一个对象啦)。

spring看到@PostConstruct就会在实例化本Bean后接着执行这个方法;

spring看到@PreDestroy就会在销毁之前执行下面的方法;

spring容器的三座大山:XML配置文件(或者注解配置、bean配置等),spring容器,bean类。不管是基于XML还是基于注解,无非就是为了把bean信息注入到spring容器中

Spring框架系列 1 -- IOC和DI_第2张图片


Spring框架系列 1 -- IOC和DI_第3张图片

适用场景

Spring框架系列 1 -- IOC和DI_第4张图片


Spring IOC 的两种实现方式(接口)?

完整的bean的作业流程:

Spring框架系列 1 -- IOC和DI_第5张图片

整体是下面这样的:

简单点:

读取XML,转化并加工成BeanDefinition,实例化BeanDefinition。

具体点:

ResourceLoader加载XML配置信息后,由BeanDefinitionReader读取配置信息文件,把每个解析成BeanDefinition对象保存在注册表中。容器首先扫描注册表取出工厂后处理器,对注册表中的BeanDefinition进行加工处理。Spring容器接着从注册表中取出加工过的BeanDefinition开始着手bean实例化的事情。实例化时,首先由BeanWapper对bean进行封装,配置属性。最后利用注册表中的Bean后处理器装饰打扮,装配出一个准备就绪的Bean来。(注册表就类似于一个Map,把所有的bean,不管是业务bean,还是spring自己的bean,都放到注册表里,用的时候取出来)。

 

再具体点:

  1. ResourceLoader从系统中加载XML配置信息,并由Resource来表示。
  2. BeanDefinitionReader从Resource中读取配置信息,把配置文件中的解析成一个BeanDefinition对象,然后把BeanDefinition对象放到BeanDefinitionRegistry注册表中。
  3. 容器从BeanDefinitionRegistry注册表中扫描出Bean工厂后处理器的Bean(该Bean实现了BeanFactoryPostProcessor),用这个工厂后处理器来加工BeanDefinitionRegistry注册表中的所有BeanDefinition对象。具体做了两件事:
    1.   对使用到元素的占位符的Bean进行解析,把占位符转换成具体值,从而把半成品的BeanDefinition对象转为成品的对象。
    2.   扫描BeanDefinitionRegistry注册表中的所有BeanDefinition对象,通过java反射机制找出所有属性编辑器的Bean(实现了PropertyEditor的Bean),然后把它放到属性编辑器注册表中(PropertyEditorRegistry)。
  4. 容器从BeanDefinitionRegistry中取出加工过的BeanDefinition,并调用InstantiationStrategy着手bean的实例化工作。
  5. 在实例化Bean时,Spring容器使用BeanWrapper对Bean进行封装,BeanWrapper结合BeanDefinition以及属性编辑器完成Bean属性的设置工作。
  6. 利用容器中注册的Bean后处理器(该Bean实现了BeanPostProcessor)对第五步生成的Bean进行后续加工。

从实例化的过程中可以看出,BeanDefinition起到中流砥柱的作用。因为BeanDefinition是配置文件元素标签在容器中的内部表示。比如,标签在XML中有class,scope,lazy-init等属性,那么在BeanDefinition中则有相应的beanClass,scope,lazyInit属性等。

BeanDefinition接口的继承结构如图:

Spring框架系列 1 -- IOC和DI_第6张图片

顶级的BeanDefinition其实是个接口,下面的AbstractBeanDefinition实现了这个接口,而最下面的ChildBeanDefinition和RootBeanDefinition分别继承了AbstractBeanDefinition。

半成品的BeanDefinition对象:
  
     
     
     
   

1.        BeanFactory接口

org.springframework.beans包中的BeanFactory接口,BeanFactory接口提供了IoC容器最基本功能(工厂模式).(如图)

Spring框架系列 1 -- IOC和DI_第7张图片


Spring框架系列 1 -- IOC和DI_第8张图片

BeanFactory 有三个子类:ListableBeanFactory、HierarchicalBeanFactory 和AutowireCapableBeanFactory。

最终的默认实现类是 DefaultListableBeanFactory : ListableBeanFactory 接口表示这些 Bean 是可列表的,而 HierarchicalBeanFactory 表示的是这些 Bean 是有继承关系的,也就是每个Bean 有可能有父 Bean。AutowireCapableBeanFactory 接口定义 Bean 的自动装配规则。这四个接口共同定义了 Bean 的集合、Bean 之间的关系、以及 Bean 行为.

BeanFactory实现:

1: DefaultListableBeanFactory(是Spring注册及加载Bean的默认实现)

2: XmlBeanDefinationReader(是XML文件的读取和注册也就是:资源文件的读取、解析和注册)

步骤1、BeanFactory(继承的是DefaultListableBeanFactory),提供基本的IoC容器功能,可以从classpath或文件系统等获取资源;

步骤2、利用ClassPathResource

Resource cr = new ClassPathResource("applicationContext.xml");
Resource resource = new FileSystemResource(“beans.xml”);  
BeanFactory beanFactory = new XmlBeanFactory(resource); 

2、  ApplicationContext接口(扩展了BeanFactory

而org.springframework.context包下的ApplicationContext接口扩展了BeanFactory,还提供了与Spring AOP集成、国际化处理、事件传播及提供不同层次的context实现 (如针对web应用的WebApplicationContext)。BeanFactory提供了IoC容器最基本功能,而 ApplicationContext 则增加了更多支持企业级功能支持。ApplicationContext完全继承BeanFactory,因而BeanFactory所具有的语义也适用于ApplicationContext。

Spring框架系列 1 -- IOC和DI_第9张图片

ApplicationContext实现:

1、 ClassPathXmlApplicationContext(继承了抽象类):,从classpath获取配置文件;

BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath.xml");  

2、FileSystemXmlApplicationContext:从文件系统获取配置文件。

BeanFactory beanFactory = new FileSystemXmlApplicationContext("fileSystemConfig.xml");

3.利用XmlWebApplicationContext读取

XmlWebApplicationContext ctx = new XmlWebApplicationContext();  

概述:ApplicationContext是Spring提供的一个高级的IoC容器,它除了能够提供IoC容器的基本功能外,还为用户提供了以下的附加服务。

从ApplicationContext接口的实现,我们看出其特点(比起BeanFactory):

         1. 支持信息源,可以实现国际化。(实现MessageSource接口)

         2. 访问资源。(实现ResourcePatternResolver接口)

         3. 支持应用事件。(实现ApplicationEventPublisher接口)

         4.  提供附加服务(更面向框架的使用风格)


1、准备配置文件:在项目中使用Spring(初始化/引入配置文件)

在配置文件中声明Bean定义也就是为Bean配置元数据。

方式1. 直接加载ApplicationContext

    ApplicationContext ctx = new ClasspathXmlApplicationContext("applicationContext.xml");  

方式2. 使用ContextLoaderListener


从ServletContext取得web.xml中初始化的ApplicationContext

在web.xml中配置listener

      
                contextConfigLocation  
                classpath: ApplicationContext.xml  
              
              
                org.springframework.web.context.ContextLoaderListener  
              

  解释:
         org.springframework.web.context.ContextLoaderListener
实现了 javax.servlet.ServletContextListener接口。ServletContextListener接口能够监听ServletContext对象的生命周期,因为每个web应用仅有一个ServletContext对象,故实际上该接口监听的是整个web应用

方式3.使用 AnnotationConfigApplicationContext 注册配置类

1、使用 AnnotationConfigApplicationContext 注册 AppContext 类

public static void main(String[] args) {  
  ApplicationContext ctx = new AnnotationConfigApplicationContext(AppContext.class);  
  Course course = ctx.getBean(Course.class);  
  course.getName();  
}  

正如以上代码所示,AppContext 配置类的注册方式是将其传递给 AnnotationConfigApplicationContext 构造函数。此外,您还可以使用所述上下文类的 register 方法来注册配置类。以下代码展示了另外一种方法。

 2、注册 AppContext 类:另外一种方法

    public static void main(String[] args) {  
      ApplicationContext ctx = new AnnotationConfigApplicationContext();  
      ctx.register(AppContext.class)  
    }  

注册配置类将自动注册 @Bean 注释的方法名称,因而其对应的 bean 就是 Course、Module 和 Assignment。随后您可以使用 getBean 方法来获取相关的 bean,并调用其业务方法。如您所见,编写 Java 的配置类并将其注册到 Spring 上下文非常简单。下一节将讨论如何将基于 Java 的配置与 Web 应用程序配合使用。




 资源Resource:

Resource是Sping中用于封装I/O操作的接口。在创建spring容器时,通常要访问XML配置文件(步骤1),除此之外还可以通过访问文件类型、二进制流等方式访问资源,还有当需要网络上的资源时可以通过访问URL,Spring把这些文件统称为Resource,Resource的体系结构如下:

Spring框架系列 1 -- IOC和DI_第10张图片

常用的resource资源类型如下:

   FileSystemResource:以文件的绝对路径方式进行访问资源,效果类似于Java中的File;

     ClassPathResourcee:以类路径的方式访问资源,效果类似于this.getClass().getResource("/").getPath();

   ServletContextResource:web应用根目录的方式访问资源,效果类似于request.getServletContext().getRealPath("");

   UrlResource:访问网络资源的实现类。例如file: http: ftp:等前缀的资源对象;

   ByteArrayResource: 访问字节数组资源的实现类。


资源加载器ResourceLoader:

Spring框架系列 1 -- IOC和DI_第11张图片

spring Bean定义解析器:

Spring框架系列 1 -- IOC和DI_第12张图片

 实体解析器,dtd, schema解析类图:

Spring框架系列 1 -- IOC和DI_第13张图片

属性编辑器(太多了只列出了部分),注册器:

Spring框架系列 1 -- IOC和DI_第14张图片


 环境相关类图:

Spring框架系列 1 -- IOC和DI_第15张图片













你可能感兴趣的:(spring框架,spring,java,SSM)