Spring技术手册笔记(一):入门、Bean、消息、事件

Spring的核心是个lightweitht 的container,他是实现IOC容器、非侵入性(No Intrusive)的框架,并提供AOP概念的实现方式,提供Persistence、transaction的支持,提供MVC Web框架的实现,并对一些常用的企业服务API提供一致的模型封装,是一个全方位的Application Framework。

一、Spring部分术语介绍

No Intrusive:应用程序几乎感觉不到框架的存在,减低应用程序在框架移植时的负担,进一步增加应用程序组件的Reusability。

控制反转(IoC):依赖关系的转移。程序不应依赖实现,而是依赖于接口。

即如果A依赖B,则B拥有控制权。依赖关系的反转即是控制关系的反转,将控制权由实现的一方转移至抽象的一方,藉由让抽象方拥有控制权,可以获得组件的壳重用性。

在例子中,整个控制权从实际的FloppyWriter转移到抽象的IDeviceWriter接口上m而让Business依赖于IDeviceWriter接口,而FloppyWriter和UsbDiskWriter也依赖于IDeviceWriter接口。

依赖注入(Dependency Injection):IoC模式是一个高层的模式概念,实现IoC有两种方式:Dependency Injection和Service Locator,Spring采用的是DI。

保留抽象接口,让组件依赖于抽象接口,当组件要与其他实际的对象发生依赖关系时,通过抽象接口来注入依赖的实际对象。

依赖注入的三种实现方式:Interface Injection、Setter Injection、Constructor Injection。

二、第一个Spring程序。

载入配置文件:

1 Resource rs  =   new  ClassPathResource( " SpringDemo\\applicationContext.xml " );
2 BeanFactory factory  =   new  XmlBeanFactory(rs);

ClassPathResource:从系统的类路径中加载,在上述的代码中,目录的层次结构如下图所示:


FileSystemResource:从文件系统加载,比如说自己指定配置文件的全路径 

InputStreamResource:从输入流中加载 

ServletContextResource:从Servlet 上下文环境中加载 

UrlResource:从指定的Url加载 

一、Bean、消息、事件

1. BeanFactory、ApplicationContext

BeanFactory负责读取Bean定义文件,管理对象的加载、生成,维护Bean对象与Bean对象之间的依赖关系,负责Bean的生命周期。

ApplicationContext具备如BeanFactory基本的容器管理功能之外,还提供一个应用程序所需的更完整的框架功能,如取得资源文件的更方便的方法,提供文字消息解析的方法,支持国际化消息,事件的发布、处理与传播等。

建议用ApplicationContext替代BeanFactory。在实现ApplicationContext的类中,最常用的是以下三个:

org.springframework.context.support.FileSystemXmlApplicationContext:可指定XML定义文件的相对路径或者绝对路径来读取定义文件。

org.springframework.context.support.ClassPathXmlApplicationContext:从Classpath设定路径中来读取XML定义文件。

2. 使用Constructor Injection

即使使用Constructor Injection,也建议定义一个无参构造方法,以让Spring可以有使用无参构造方法来生成对象的弹性。

在Bean定义文件中,必须指定构造方法上参数的顺序,如下

< bean  id ="hello"  class ="SpringDemo.HelloBean" >
    
< constructor-arg  index ="0"  value ="codingliyi"   />
    
< constructor-arg  index ="1"  value ="Hello"   />
</ bean >

建议使用Setter构造方法。有时需要隐藏某属性的Setter方法时(如使该属性变为只读或私有),可使用Constructor Injection。

3. 属性绑定

如某个Bean实例只被某个属性参考一次,之那么可以在属性定义时使用Bean标签,并仅需指定其class属性即可。

1 < property  name ="date" >
2      < bean  class ="java.util.Date" />
3 </ property >

Spring也支持隐式的自动绑定。

1 < bean  id ="helloBean"  class ="SpringDemo.HelloBean"  autowire ="byType|byName|constructor|autodetect"  dependency-check ="simple|objects|all|none" />

若使用byType无法完成绑定,则抛出异常;

若使用byName无法完成绑定,则对应得Setter仅维持未绑定状态;

若使用constructor,Spring容器会试图比较对应容器中的Bean实例类型,及相关构造方法上的参数类型;

若使用autodetect,Spring首先尝试constructor,不行的话再尝试byType。

dependency-check指定依赖检查的方式,默认为none。如进行依赖检查时发现有未完成的伊拉关系,则执行时会跑出异常。

4. 集合类属性的注入。

< property  name ="list|set" >
    
< list |set >
        
< value > hello </ value >
        
< ref  bean ="helloBean" />
    
</ list|set >
</ property >
< property  name ="map" >
    
< map >
        
< entry  key ="name"  value ="codingliyi"   />
        
< entry  key ="person" >
            
< ref  bean ="codingliyi" />
        
</ entry >
    
</ map >
</ property >
< property  name ="properties" >
    
< props >
        
< prop  key ="name" > codingliyi </ prop >
    
</ props >
</ property >

 

5. Bean的生命周期

使用BeanFactory来生成及管理Bean实例时:

Bean的建立:读取Bean定义文件,生成Bean的实例。

属性注入:执行相关Bean属性的依赖注入。

BeanNameAware的setBeanName():

如Bean实现了BeanNameAware接口,则执行。

BeanFactoryAware的setBeanFactory():

如Bean实现了BeanFactoryAware接口,则执行。

BeanPostProcessors的processBeforeInitialization():

如任何BeanPostProcessors实例与Bean实例关联,则执行。

InitializingBean的afterPropertiesSet()

如Bean实现了InitializingBean接口,则执行。

Bean定义文件中定义的init-method

如定义了init-method,则执行设定的方法名称。

BeanPostProcessors的processAfterInitialization():

如任何BeanPostProcessors实例与Bean实例关联,则执行。

DisposableBean的destory()

如Bean实现了DisposableBean接口,则执行。

Bean定义文件中定义的destory-method

如定义了destory-method,则执行设定的方法名称。

若使用ApplicationContext,在执行setBeanFactory()后,若bean有实现ApplicationContextAware接口,则执行setApplicationContext(),接着再继续执行之后的流程。

6. Bean高级管理

Aware接口

有时为了善用Spring所提供的一些功能,必须让Bean知道Spring容器管理的一些细节,或者让它知道BeanFactory,ApplicationContext的存在。

Spring中提供了一些Aware接口。如BeanNameAware,BeanFactoryAware,ApplicationContextAware。

当Bean实现了上述接口后,在依赖关系设定完成之后,初始化方法之前,Spring容器会注入对应的实例。

(在暑期实习中做的那个Flex项目,需要在Action层使用ApplicationContext得到服务层组件。当时使用的是直接在代码中用new创建。其实现在看来可以实现ApplicationContextAware接口)

BeanPostProcessor接口

1 public   interface  BeanPostProcessor  {    
2    public Object postProcessAfterInitialization(Object bean, String name)throws BeansException;
3
4    public Object postProcessBeforeInitialization(Object bean, String name)throws BeansException;
5    }

6 }

    例如将注入的String改为大写,代码如下:

 1 public  Object postProcessBeforeInitialization(Object bean, String name)
 2          throws  BeansException  {
 3    Field[] fields = bean.getClass().getDeclaredFields();
 4    for(Field field : fields){
 5        if(field.getType().equals(String.class)){
 6            try {
 7                String original = (String)field.get(bean);
 8                field.set(bean, original.toUpperCase());
 9            }
 catch (IllegalArgumentException e) {
10                e.printStackTrace();
11            }
 catch (IllegalAccessException e) {
12                e.printStackTrace();
13            }

14        }

15    }

16    return bean;
17}


7. 
资源、消息、事件

ApplicationContext除了具备如BeanFactory基本的容器管理功能之外,并支持更多应用框架的特性,像是资源的取得、消息解析、事件的处理与传播。

资源的取得:ApplicationContext继承了ResourceLoader接口,可使用getResource()方法并指定资源文件的URL来取得一个实现Resource接口的实例。

Resource resource = context.getResource("classpath:admin.properties");

也可以指定其他标准的URL,如file:或http:等。

在Spring应用程序执行期间,ApplicationContext本身就会发布一连串的事件,而所有发布的时间都是抽象类ApplicationEvent的子类。

ApplicationContext会在ApplicationEvent发布时通知实现了ApplicationListener的Bean类实例。

如果打算发布事件通知ApplicationListener的实例,则可使用ApplicationContext的publishEvent()方法。




你可能感兴趣的:(Spring技术手册笔记(一):入门、Bean、消息、事件)