spring知识点整理-第一篇

1、@Autowired与@Resource前端

 相同点:均可以用来装配bean. 均可以写在字段上,或写在setter方法上。       java

不一样点:1.@Autowired 默认按类型装配(这个注解是属业spring的),默认状况下必需要求依赖对象必须存在,若是要容许null值,能够设置它的required属性为false,如:@Autowired(required=false);若是咱们想使用名称装配能够结合@Qualifier注解进行使用 。程序员

2.@Resource 默认安装名称进行装配(这个注解属于J2EE的),名称能够经过name属性进行指定,若是没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,若是注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。可是须要注意的是,若是name属性一旦指定,就只会按照名称进行装配。推荐使用:@Resource注解在字段上,这样就不用写setter方法了,而且这个注解是属于J2EE的,减小了与spring的耦合。注意:若是没有指定name属性,而且按照默认的名称仍然找不到依赖对象时,@Resourve注解会回退到按类型装配。但一旦指定了name属性,就只能按照名称装配了。web

代码:spring

@Resource(name="testService")  
private TestService testService;

2、spring bean的做用域分为如下五种:sql

一、singleton(默认模式):单例,指一个bean容器中只存在一份。编程

二、prototype:每次请求(每次使用)建立新的实例,destroy方式不生效。设计模式

三、request:每次http请求建立一个实例且仅在当前request内有效。session

四、session:同上,每次http请求建立,当前session中有效。mvc

五、global session:基于portlet的web中有效(portlet定义了global sessio),若是在web中,同session。

代码:

a.xml的配置

<!-- 设置bean的做用域scope属性值为prototype,默认为singleton,能够不设置scope属性 -->
<bean name="beanScope" class="com.jsun.test.springDemo.BeanScope" scope="prototype"></bean>

b.annotation注解方式

//注册bean
@Component("beanScope") 
//设置bean的做用域范围为singleton
@Scope("singleton")  
public class BeanScope {

}

3、spring bean的生命周期

一、xml文件中配置bean的init-method属性和destroy-method属性

<bean name="beanScope" class="com.jsun.test.springDemo.BeanScope" 
init-method="init_m" destroy-method="destroy_m"></bean>

同时须要注意的是:若是bean中配置init-method和init-destroy属性,那么在bean类中必须提供对应的初始化和销毁方法,不然将抛出初始化异常:Exception encountered during context initialization 。若是配置全局的,在<beans></beans>上进行配置。

二、实现

org.springframework.beans.factory.DisposableBean/org.springframework.beans.factory.InitializingBean接口,覆盖实现afterPropertiesSet()和destroy()方法.

public class BeanScope implements InitializingBean,DisposableBean {

    public BeanScope(){
        System.out.println("BeanScope 实例化");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("实现接口InitializingBean afterPropertiesSet()初始化");

    }

    @Override
    public void destroy() throws Exception {
        System.out.println("实现接口DisposableBean destroy()销毁");

    }
}

注:若是配置了bean的init-method和init-destroy属性(或同时配置全局的default-init-method和default-destroy-method属性),并实现了上述的初始化和销毁接口,接口的初始化和销毁方法将先于配置的初始化和销毁方法。

三、注解配置方式

在指定方法上加上@PostConstruct或@PreDestroy注解来指定该方法做为初始化或销毁方法来使用。

public class BeanScope{

    public BeanScope(){
        System.out.println("BeanScope bean 实例化");
    }

    //添加@PostConstruct注解,指定当前方法做为初始化方法
    @PostConstruct
    public void init(){
        System.out.println("@PostConstruct注解 初始化");
    }

    //添加@PreDestroy注解,指定当前方法做为销毁方法
    @PreDestroy
    public void destroy(){
        System.out.println("@PreDestroy注解 销毁");
    }
}

4、bean的做用域与生命周期之间的关系以及初始化时机

一、初始化bean实例是时机与bean做用域的关系

(1)、当scope=singleton,即默认状况,会在容器初始化时实例化、初始化。但若是指定bean节点的lazy-init=”true”,来延迟bean的实例化、初始化,当第一次获取bean时才会初始化bean。

(2)、当scope=prototype时,也会延迟初始化bean,至关于设置lazy-init=”true”,即第一次请求该bean时才初始化(如调用getBean()方法时);而且当spring容器关闭时,destroy()销毁方法也不会被调用。

缘由:对于prototype做用域的bean,有一点很是重要,那就是Spring不能对一个prototype bean的整个生命周期负责:容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例漠不关心了。无论何种做用域,容器都会调用全部对象的初始化生命周期回调方法。但对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。

5、InitializingBean的做用

InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候会执行该方法。

import org.springframework.beans.factory.InitializingBean;
public class TestInitializingBean implements InitializingBean{
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("ceshi InitializingBean");        
    }
    public void testInit(){
        System.out.println("ceshi init-method");        
    }
}

在spring初始化bean的时候,若是该bean是实现了InitializingBean接口,而且同时在配置文件中指定了init-method,系统则是先调用afterPropertiesSet方法,而后在调用init-method中指定的方法。

总结

1:spring为bean提供了两种初始化bean的方式,实现InitializingBean接口,实现afterPropertiesSet方法,或者在配置文件中同过init-method指定,两种方式能够同时使用。

2:实现InitializingBean接口是直接调用afterPropertiesSet方法,比经过反射调用init-method指定的方法效率相对来讲要高点。可是init-method方式消除了对spring的依赖。

3:若是调用afterPropertiesSet方法时出错,则不调用init-method指定的方法。

6、ApplicationContextAware、ApplicationListener的做用和关于spring中Aware结尾接口介绍

一、首先来介绍以Aware为结尾接口

Spring中提供一些Aware结尾相关接口,像是BeanFactoryAware、 BeanNameAware、ApplicationContextAware、ResourceLoaderAware、ServletContextAware等等。实现这些 Aware接口的Bean在被实例化 以后,能够取得一些相对应的资源,例如实现BeanFactoryAware的Bean在实例化后,Spring容器将会注入BeanFactory的实例,而实现ApplicationContextAware的Bean,在Bean被实例化后,将会被注入 ApplicationContext的实例等等。经过重写setter方法,当前bean被实例化后实现相关实例的注入。

//实现BeanNameAware接口,并重写setBeanName()方法,让Bean获取本身在BeanFactory配置中的名字
//(根据状况是id或者name)
//实现ApplicationContextAware接口,并重写setApplicationContext()方法
public class MyApplicationContext implements BeanNameAware,ApplicationContextAware{
    private String beanName;

    //注入的beanName即为MyApplicationContext在BeanFactory配置中的名字(根据状况是id或者name)
    @Override
    public void setBeanName(String beanName) {
        this.beanName = beanName;
        System.out.println("MyApplicationContext beanName:"+beanName);
    }

    @Override
    public void setApplicationContext(ApplicationContext context)
            throws BeansException {
        //经过重写的接口方法,获取spring容器实例context,进而获取容器中相关bean资源
        System.out.println(context.getBean(this.beanName).hashCode());

    }

}

注意:除了经过实现Aware结尾接口获取spring内置对象,也能够经过@Autowired注解直接注入相关对象,(若是须要用到静态方法中,如工具方法,仍是采用实现接口的方式).

二、ApplicationContextAware、ApplicationListener的做用

什么是ApplicationContext? 
它是Spring的核心,Context咱们一般解释为上下文环境,可是理解成容器会更好些。 
ApplicationContext则是应用的容器。Spring把Bean(object)放在容器中,须要用就经过get方法取出来。

ApplicationEvent

是个抽象类,里面只有一个构造函数和一个长整型的timestamp。
ApplicationListener

是一个接口,里面只有一个onApplicationEvent方法。因此本身的类在实现该接口的时候,要实装该方法。若是在上下文中部署一个实现了ApplicationListener接口的bean,那么每当在一个ApplicationEvent发布到 ApplicationContext时,这个bean获得通知。其实这就是标准的Oberver设计模式。

其中ApplicationContextAware接口能够实现咱们在初始化bean的时候给bean注入ApplicationConxt(Spring上下文对象)对象。ApplicationContextAware接口提供了publishEvent方法,实现了Observe(观察者)设计模式的传播机制,实现了对bean的传播。经过ApplicationContextAware咱们能够把系统中全部ApplicationEvent传播给系统中全部的ApplicationListener。所以,咱们只须要构造好咱们本身的ApplicationEvent和ApplicationListener,就能够在系统中实现相应的监听器。

资料:http://blog.csdn.net/u011955252/article/details/52900690

7、BeanDefinition、PropertyEditorSupport的做用

1.BeanDefinition

将Bean的定义信息存储到这个BeanDefinition相应的属性中,后面对Bean的操做就直接对BeanDefinition进行,例如拿到这个BeanDefinition后,能够根据里面的类名、构造函数、构造函数参数,使用反射进行对象建立。BeanDefinition是一个接口,是一个抽象的定义,实际使用的是其实现类,如ChildBeanDefinition、RootBeanDefinition、GenericBeanDefinition等。BeanDefinition继承了AttributeAccessor,说明它具备处理属性的能力;BeanDefinition继承了BeanMetadataElement,说明它能够持有Bean元数据元素,做用是能够持有XML文件的一个bean标签对应的Object。

详细解读的流程资料:http://blog.51cto.com/dba10g/1726519

二、PropertyEditorSupport

经过继承JDK 中的 java.beans.PropertyEditorSupport 类来实现本身的编辑器类 ,该类用于实现将String 类型转换成您须要的数据类型。而后咱们只须要在Spring 的容器中对这个编辑器进行有效的“注册”即可以实现Spring 在装配Bean 时自动的将String 类型转换成咱们自定义的类型。

如何编辑本身的PropertyEditor,其实须要了解一点java.beans包的知识,在该包中,有一个 java.beans.PropertyEditor的接口,它定义了一套接口方法(12个),即经过这些方法如何将一个String变成内部的一个对 象,这两个方法是比较重要的: 
     a)setValue(Object value) 直接设置一个对象
     b)setAsText(String text) 经过一个字符串来构造对象,通常在此方法中解析字符串,将构造一个类对象,调用setValue(Object)来完成属性对象设置操做。 
  2)实现全部的接口方法是麻烦的,java.beans.PropertyEditorSupport 适时登场,通常状况下,咱们经过扩展这个方便类便可。好比转换时间格式:

import java.beans.PropertyEditorSupport;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Date;

import org.jflame.toolkit.util.DateHelper;
import org.springframework.util.StringUtils;

/**
 * 多日期格式转换器<p>
 * 默认支持格式:"yyyy-MM-dd","yyyy-MM-dd HH:mm:ss","yyyy年MM月dd日","yyyyMMddHHmmss"
 * 
 *
 */
public class MyCustomDateEditor extends PropertyEditorSupport {
	
	private final DateFormat defaultDateFormat;
	
	public MyCustomDateEditor(){
		defaultDateFormat=null;
	}
	
	/**
	 * 构造函数,指定特定格式DateFormat
	 * @param dateFormat
	 */
	public MyCustomDateEditor(DateFormat dateFormat) {
		this.defaultDateFormat = dateFormat;
	}
	
	/**
	 * Parse the Date from the given text, using the specified DateFormat.
	 */
	@Override
	public void setAsText(String text) throws IllegalArgumentException {
		if (!StringUtils.hasText(text)) {
			setValue(null);
		}
		else {
			try {
				//未指定固定格式器,使用全部支持格式处理
				if(defaultDateFormat==null){
					setValue(DateHelper.parseDate(text, DateHelper.formats));
				}else{
					setValue(this.defaultDateFormat.parse(text));
				}
			}
			catch (ParseException ex) {
				throw new IllegalArgumentException("Could not parse date: " + ex.getMessage(), ex);
			}
		}
	}

	/**
	 * Format the Date as String, using the specified DateFormat.
	 */
	@Override
	public String getAsText() {
		Date value = (Date) getValue();
		String dateStr = "";
		if (value != null) {
			if (defaultDateFormat == null) {
				if (value instanceof java.sql.Date) {
					dateStr = DateHelper.format(value, DateHelper.CN_YYYY_MM_DD);
				} else {
					dateStr = DateHelper.format(value, DateHelper.YYYY_MM_DD_HH_mm_ss);
				}
			} else {
				dateStr = this.defaultDateFormat.format(value);
			}
		}
		return dateStr;
	}
}

8、@Configuration注解、@Bean注解的使用

   一、@Configuration注解、@Bean注解

 Spring中为了减小xml中配置,能够声明一个配置类(例如SpringConfig)来对bean进行配置。

咱们须要在用于指定配置信息的类上加上 @Configuration 注解,以明确指出该类是 Bean 配置的信息源。而且 Spring 对标注 Configuration 的类有以下要求: 

      (a) 配置类不能是 final 的;

      (b)配置类不能是本地化的,亦即不能将配置类定义在其余类的方法内部;

      (c)配置类必须有一个无参构造函数。

@Configuration //在类上配置注解
public class BookStoreDaoConfig{  
@Bean   //在方法上配置注解
public UserDao userDao(){
   return new UserDaoImpl();//配置类必须有一个无参构造函数
}  
@Bean  
public BookDao bookDao(){
   return new BookDaoImpl();
}  
}

注意:Spring 在解析到以上文件时,将识别出标注 @Bean 的全部方法,执行之,并将方法的返回值 ( 这里是 UserDaoImpl 和 BookDaoImpl 对象 ) 注册到 IoC 容器中。默认状况下,Bean 的名字即为方法名。

a.@Bean 具备如下四个属性:  

name -- 指定一个或者多个 Bean 的名字。这等价于 XML 配置中 的 name 属性。

initMethod -- 容器在初始化完 Bean 以后,会调用该属性指定的方法。这等价于 XML 配置中 的 init-method 属性。

destroyMethod -- 该属性与 initMethod 功能类似,在容器销毁 Bean 以前,会调用该属性指定的方法。这等价于 XML 配置中 的 destroy-method 属性。

autowire -- 指定 Bean 属性的自动装配策略,取值是 Autowire 类型的三个静态属性。

      1. Autowire.BY_NAME,

       2.Autowire.BY_TYPE,

       3.Autowire.NO。

与 XML 配置中的 autowire 属性的取值相比,这里少了 constructor,这是由于 constructor 在这里已经没有意义了。@Bean 没有直接提供指定做用域的属性,能够经过 @Scope 来实现该功能。

b.@Configuration注解

@Target({ElementType.TYPE})  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
@Component  
public @interface Configuration {  
String value() default "";  

9、@Value和<util:properties>的使用

资料:http://blog.csdn.net/wangshfa/article/details/26674839

10、spring中的父子容器

spring总的上下文容器有父子之分,父容器和子容器。 父容器对子容器可见,子容器对父容器不可见 。

父子容器的主要用途是上下文隔离。以spring和SpringMVC为例子。须要先熟悉spring是怎样在web容器中启动起来的。spring的启动过程其实就是其IoC容器的启动过程,对于web程序,IoC容器启动过程便是创建上下文的过程。

spring的启动过程:

  1. 首先,对于一个web应用,其部署在web容器中,web容器提供其一个全局的上下文环境,这个上下文就是ServletContext,其为后面的spring IoC容器提供宿主环境;

  2. 其次,在web.xml中会提供有contextLoaderListener。在web容器启动时,会触发容器初始化事件,此时contextLoaderListener会监听到这个事件,其contextInitialized方法会被调用,在这个方法中,spring会初始化一个启动上下文,这个上下文被称为根上下文,即WebApplicationContext,这是一个接口类,确切的说,其实际的实现类是XmlWebApplicationContext。这个就是spring的IoC容器,其对应的Bean定义的配置由web.xml中的context-param标签指定。在这个IoC容器初始化完毕后,spring以WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE为属性Key,将其存储到ServletContext中,便于获取;

  3. 再次,contextLoaderListener监听器初始化完毕后,开始初始化web.xml中配置的Servlet,这个servlet能够配置多个,以最多见的DispatcherServlet为例,这个servlet其实是一个标准的前端控制器,用以转发、匹配、处理每一个servlet请求。DispatcherServlet上下文在初始化的时候会创建本身的IoC上下文,用以持有spring mvc相关的bean。在创建DispatcherServlet本身的IoC上下文时,会利用WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE先从ServletContext中获取以前的根上下文(即WebApplicationContext)做为本身上下文的parent上下文。有了这个parent上下文以后,再初始化本身持有的上下文。这个DispatcherServlet初始化本身上下文的工做在其initStrategies方法中能够看到,大概的工做就是初始化处理器映射、视图解析等。这个servlet本身持有的上下文默认实现类也是mlWebApplicationContext。初始化完毕后,spring以与servlet的名字相关(此处不是简单的以servlet名为Key,而是经过一些转换,具体可自行查看源码)的属性为属性Key,也将其存到ServletContext中,以便后续使用。这样每一个servlet就持有本身的上下文,即拥有本身独立的bean空间,同时各个servlet共享相同的bean,即根上下文(第2步中初始化的上下文)定义的那些bean。

何为父子上下文呢?

父上下文:

使用listener监听器来加载配置文件,以下:

<listener>   

  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>   

</listener>


Spring 会建立一个WebApplicationContext上下文,称为父上下文(父容器),保存在 ServletContext中,key是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE的值。

可使用Spring提供的工具类取出上下文对象:WebApplicationContextUtils.getWebApplicationContext(ServletContext);

子上下文:

使用Spring MVC 来处理拦截相关的请求时,会配置DispatchServlet:

<servlet>

    <servlet-name>dispatcherServlet</servlet-name>

    <servlet-class>org.springframework.web.servlet.DispatcherServlet

    </servlet-class>

    <init-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>/WEB-INF/applicationContext-mvc.xml</param-value>

    </init-param>

    <load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

    <servlet-name>dispatcherServlet</servlet-name>

    <url-pattern>/</url-pattern>

</servlet-mapping>


每一个DispatchServlet会有一个本身的上下文,称为子上下文,它也保存在 ServletContext中,key 是"org.springframework.web.servlet.FrameworkServlet.CONTEXT"+Servlet名称。当一 个Request对象产生时,会把这个子上下文对象(WebApplicationContext)保存在Request对象中,key是 DispatcherServlet.class.getName() + ".CONTEXT"。

可使用工具类取出上下文对象:RequestContextUtils.getWebApplicationContext(request);

父上下文(父容器)和子上下文(子容器)的访问权限:

子上下文能够访问父上下文中的bean,可是父上下文不能够访问子上下文中的bean。

父上下文使用与否

方案一,传统型:

父上下文容器中保存数据源、服务层、DAO层、事务的Bean。

子上下文容器中保存Mvc相关的Action的Bean.

事务控制在服务层。

因为父上下文容器不能访问子上下文容器中内容,事务的Bean在父上下文容器中,没法访问子上下文容器中内容,就没法对子上下文容器中Action进行AOP(事务)。

固然,作为“传统型”方案,也没有必要这要作。

方案二,激进型:

Java世界的“面向接口编程”的思想是正确的,但在增删改查为主业务的系统里,Dao层接口,Dao层实现类,Service层接口,Service层实现类,Action父类,Action。再加上众多的O(vo\po\bo)和jsp页面。写一个小功能 七、8个类就写出来了。 开发者说我就是想接点私活儿,和PHP,ASP抢抢饭碗,但我又是Java程序员。最好的结果是大项目能作好,小项目能作快。因此“激进型”方案就出现了-----没有接口、没有Service层、还能够没有众多的O(vo\po\bo)。那没有Service层事务控制在哪一层?只好上升的Action层。

本文不想说这是否是正确的思想,我想说的是Spring不会限制你这样作。

因为有了父子上下文,你将没法实现这一目标。解决方案是只使用子上下文容器,不要父上下文容器 。因此数据源、服务层、DAO层、事务的Bean、Action的Bean都放在子上下文容器中。就能够实现了,事务(注解事务)就正常工做了。这样才够激进。

总结:不使用listener监听器来加载spring的配置文件,只使用DispatcherServl

11、@DependsOn注解的做用

相关文章
相关标签/搜索