天天看點

BeanFactory and ApplicationContext in Spring

BeanFactory and ApplicationContext in Spring

          BeanFactory和ApplicationContext 是使用過Spring的同學耳熟能詳的兩個接口,其中BeanFactory是Spring架構最核心的接口,之前學習Spring開發的時候接觸多的是ApplicationContext 這個面向應用的功能,當然要搭建Spring環境也可以不用了解BeanFactory這個接口,簡而言之:

BeanFactor:y提供了進階的IoC的配置機制,管理不同類型的Java對象,是Spring架構的基礎設施,面向的是Spring本身。

ApplicationContext:是建立在BeanFactory基礎之上的,它提供了更多的面向應用的功能,諸如國際化支援,架構事件體系,易于建立實際應用,面向使用Spring的開發者。

這裡先說說Spring裡面的Resource接口:

Resource:為應用提供了強大的通路底層資源,下面UML列出了它的主要接口和雞翅根體系:

BeanFactory and ApplicationContext in Spring

這三個是常用的,這三個子類可以見名知意了,還有如:

InputStreamResource:對應的是InputStream的資源。

ServletContxtResource:負責Web應用根目錄的路徑加載資源,支援URL的方式通路,可以直接從jar包中通路資源。

UrlResource:可以通路任何可以通過URL表示的資源,如HTTP資源,FTP資源。

FileSystemResource:

public class FileSourceDemo {

	public static void main(String[] args) {

		String filePath = "E:\\Workspace_64bit\\Myeclipses_spring3.x\\spring3_learning\\WebRoot\\WEB-INF\\spring3-servlet.xml";
		Resource res1 = new FileSystemResource(filePath);
		Resource res2 = new ClassPathResource("WEB-INF\\spring3-servlet.xml");
//		Resource res3 = new ServletContextResource(servletContext, "")
		System.out.println(res1.getFilename());
		try {
			System.out.println(res1.getURL());
			System.out.println(res1.getFile());
			System.out.println(res2.getFilename());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
           

@上面分别以系統檔案路徑和類路徑讀取本地資源檔案,常用的是ClassPathResource,這樣在工程移植的時候就不會出現路徑問題。

SerlvetContextResource:

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<jsp:directive.page import="org.springframework.web.context.support.ServletContextResource"/>
<jsp:directive.page import="org.springframework.core.io.Resource"/>
<jsp:directive.page import="org.springframework.web.util.WebUtils"/>
<%
   Resource res = new ServletContextResource(application,"/WEB-INF/classes/conf/testFile.txt");
   out.print(res.getFilename()+"<br/>");
   out.print(WebUtils.getTempDir(application).getAbsolutePath());
%>
           

@輸出結果為:

testFile.txt

A:\Program Files (x86)\Apache Software Foundation\Tomcat 6.0\work\Catalina\localhost\spring3_chapter3

資源加載路徑表示:

常用的classpath(值加載第一個包下的資源檔案):,classpath*(加載類路徑下多個子產品多個相同報名的資源檔案):

在實際開發中常用的就是classpath路徑下加載資源檔案了,那麼Spring提供了一個強大的資源加載機制,在通過classpath:和file:标示符加載多個資源檔案大小的同時,提供了Ant風格:

? :比對檔案名中的一個字元。

*  :比對檔案名中的任意字元。

** :比對多層路徑。

要使用這些Ant風格的方式,就要用到了資源加載器,ResourceLoader:

BeanFactory and ApplicationContext in Spring

看一個小執行個體:

public class ResourceUtilsDemo {
	public static void main(String[] args) {
		ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
		try {
			//Ant風格
			// Resource[] resources = resolver
			// .getResources("classpath*:/*.xml");
			// Resource[] resources = resolver
			// .getResources("classpath*:com/**/*.xml");
			//Ant隻有在調用getResources方法傳回多個資源檔案的時候使用
			Resource[] resources = resolver
					.getResources("classpath*:/?eans.xml");
			for (Resource resource : resources) {
				System.out.println(resource.getFilename());
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
           

有了這些基礎,回到Spring:

看看BeanFactory的體系結構:

BeanFactory and ApplicationContext in Spring

@BeanFactory:提供了getBean,也就是我們常用的

@HierachicalBeanFactory:可以檢視Bean的個數,擷取Bean的配置名,檢視容器是否包某一Bean

@ConfigurableBeanFactory:增強了IoC容器的可定制性,定義了設定類裝載器,屬性編輯器,容器初始化後置處理器等。

@AutowireCapableBeanFactory:定義了将容器中的Bean按某種規則進行自動裝配的方法

@SingletonBeanRegistry:定義了允許在運作期想容器注冊單執行個體Bean的方法。

@BeanDefinitionRegistry:Spring配置檔案中的<bean>節點是通過BeanDefinition對象表示,BeanDefinition描述了Bean的配置資訊,BeanDefinitionRegistry提供了向容器手工注冊BeanDefinition對象的方法。

BeanFactory的應用,看一個小執行個體:

src目錄下,beans.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.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-3.0.xsd">
	<bean id="car" class="com.baobaotao.Car" 
		 init-method="myInit"
		 destroy-method="myDestory"
		 p:brand="紅旗CA72"
		 p:maxSpeed="200" 
		 />  
</beans>
           

在Java中使用BeanFactory:

public class BeanFactoryDemo {
	public static void main(String[] args) throws Throwable{
	   ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
	   Resource res = resolver.getResource("classpath:beans.xml");
	   System.out.println(res.getURL());
       BeanFactory bf = new XmlBeanFactory(res);
       System.out.println("init BeanFactory.");
       
       Car car = bf.getBean("car",Car.class);
       System.out.println("car bean is ready for use!");
       car.introduce();
	}
}
           

@BeanFactory#getBean方法在第一次調用時才執行個體化Bean,并存于緩存中,第二次調用的時候直接從緩存中取。

@DefaultSingletonBeanFactory提供一個Map集合實作的緩存器,用于緩存單執行個體Bean。

之前說到ApplicationContext是面向開發者的,那麼來看看ApplicationContext:

ApplicationContext:

ApplicationContext是對BeanFactory的擴充,使用過程中常用的兩個實作類

FileSystemXmlApplicationContext&&ClassPathXmlApplicationContext

ApplicationContext初始化:

public class MyApplicationContext {

	public static void main(String[] args) {
		// 擷取配置檔案
		ApplicationContext cx = new ClassPathXmlApplicationContext(
				new String[] { "beans.xml" });//傳入數組
		Person person = cx.getBean("person", Person.class);
		System.out.println(person);
	}
}
           

@擷取ApplicationContext執行個體後,可以像BeanFactory一樣調用getBean方法了

@ApplicationContext在初始化的時候會執行個體化所有單例的Bean,非單例的Bean在調用時才執行個體化,差別在與scope=“singleton/prototype”是以初始化時間比BeanFactory長。

在xml中的監聽器配置:

上述是在Java中手動獲得ApplicationContext和BeanFactory,那麼啟動容器時,怎麼加載這些配置檔案呢?需要在xml中配置一個監聽器了:

<!-- 加載配置檔案的路徑資訊 -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/applicationContext.xml</param-value>
		<!--<param-value>classpath:applicationContext.xml</param-value> -->
	</context-param>

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

@配置檔案路徑同樣支援Ant風格,監聽器是常用的,還有一個通過Servlet自啟動來實作。

Spring3新特性:基于Java類提供配置資訊:

首先我們提供一個帶有@Configuration注解的Java類:

/**
 * 通過java類提供IoC配置資訊
 * 
 * @author PingCX
 * 
 */
@Configuration
// 告訴Spring這是一個bean提供類
public class Beans {
	@Bean(name = "user")
	@Scope("prototype")
	// 指定空間,預設是singleton,初始化時執行個體化,prototype在用到時執行個體化
	// 定義一個bean
	public User createUser() {
		User user = new User();
		user.setUserName("ysjian");
		user.setUserId(1001);
		return user;
	};

	@Bean(name = "dataSource")
	public BasicDataSource createDataSource() {
		BasicDataSource dataSource = new BasicDataSource();
		dataSource.setDriverClassName("com.mysql.jdbc.Driver");
		dataSource
				.setUrl("jdbc:mysql://localhost:3306/spring3?userUnicode=true&characterEncoding=UTF-8");
		dataSource.setUsername("root");
		dataSource.setPassword("ysjian");
		return dataSource;
	}

	@Bean(name = "jdbcTemplate")
	public JdbcTemplate createjJdbcTemplate() {
		return new JdbcTemplate(createDataSource());
	}

	@Bean(name = "transactionManager")
	public DataSourceTransactionManager createdDataSourceTransactionManager() {
		return new DataSourceTransactionManager(createDataSource());
	}

	@Bean(name = "userService")
	public IUserService createUserService() {
		return new UserService();
	}

	@Bean(name = "userDao")
	public IUserDao createUserDao() {
		return new UserDao();
	}

	@Bean(name = "loginLogDao")
	public ILoginLogDao createLoginLogDao() {
		return new LoginLogDao();
	}
}
           

@這種方式在執行個體化對象的時候比較靈活的控制。

啟動容器,用到了AnnotationApplicationContext:

public class AnnotationApplicationContext {

	public static void main(String[] args) {
		//Java類提供的配置資訊
		ApplicationContext ctx = new AnnotationConfigApplicationContext(
				Beans.class);
		User user =  ctx.getBean("user",User.class);
		System.out.println(user);
	}
}
           

在xml配置檔案中的配置:

<!-- 使用@Configuration的Java類提供配置資訊 -->
	<context-param>
		<param-name>contextClass</param-name>
		<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
	</context-param>
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<!-- 指定J提供配置資訊的Java類 -->
		<param-value>com.meritit.ysjian.spring3learning.context.Beans</param-value>
	</context-param>

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

@ContextLoaderListener發現contextClass上下文參數,就會使用WebApplicationContext的實作類初始化容器,再根據contextConfigLocation上下文參數指定有@Configuration注解的Java類提供的配置資訊初始化容器。