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列出了它的主要接口和雞翅根體系:
這三個是常用的,這三個子類可以見名知意了,還有如:
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:
看一個小實例:
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();
}
}
}
看看BeanFactory的體系結構:
@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類提供的配置信息初始化容器。