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(); } } }有了这些基础,回到Spring:
看看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类提供的配置信息初始化容器。