您的位置:首页 > 编程语言 > Java开发

Spring配置文件详解

2017-09-21 22:59 302 查看

1、 关于applicationContext.xml文件开头

DTD验证XML配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd">

<beans>

<!-- bean definitions here -->

</beans>


另一种Schema验证配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- bean definitions here -->

</beans>


这个可以去spring-framework-4.3.6.RELEASE\docs\spring-framework-reference\html\xsd-configuration.html里找到 ,里面有很多配置信息

2、实例化Spring的IoC容器

2.1、使用BeanFactory

Spring的BeanFactory采用的是工厂模式,实现了BeanFactory接口的类负责创建并配置所有的Bean。应用程序将Bean的创建和配置完全委托给BeanFactory,然后从BeanFactory获取并使用它们。

BeanFactory bf = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
//在调用getBean("beanId")方法请求Bean的实例时,才调用相应的初始化方法


2. 2、使用ApplicationContext

ApplicationContext 本质上仍然是一个BeanFactory,因为ApplicationContext是从BeanFactory 继承而来的。不过,ApplicationContext 提供了更多的功能,并能够与一些应用环境整合。

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//context = new FileSystemXmlApplicationContext("");
//context = new XmlWebApplicationContext();
//实例化ApplicationContext
4000
时会自动调用Bean指定的初始化方法,


3 Bean 初始化

ApplicationContext 初始化Bean和基本的BeanFactory有所不同,基本的BeanFactory总是延迟加载Bean,直到第一次调用getBean(“beanId”)方法请求Bean的实例时,BeanFactory才会创建这个Bean,而ApplicationContext 在自身初始化时就一次性创建了所有的Bean。因此,ApplicationContext在初始化时就能验证XML配置文件的正确性,而使用基本的BeanFactory,直到调用getBean(“BeanId”)方法获取Bean实例时,才可能会发现配置错误而导致抛出异常。

3.1 Bean的初始化流程

1.容器根据XML配置文件中Bean的定义实例化一个Bean,并传入必要的构造方法参数。

2.容器根据XML配置文件使用依赖注入设置Bean的属性。

3 如果Bean实现了BeanNameAware接口,调用其setBeanName()方法。

4 如果Bean实现了BeanClassLoaderAware接口,调用其setBeanClassLoader()方法。

5.如果Bean实现了BeanFactoryAware接口,调用其setBeanFactory()方法。

6.如果使用ApplicationContext 并且Bean实现了ResourceLoaderAware接口,调用其setResourceLoader()方法。

7.如果使用ApplicationContext 并且Bean实现了ApplicationEventPublisherAware接口,调用其setApplicationEventPublisher()方法。

8.如果使用ApplicationContext 并且Bean实现了MessageSourceAware接口,调用其setMessageSource()方法。

9.如果使用ApplicationContext 并且Bean实现了ApplicationContextAware接口,调用其setApplicationContext()方法。

10.如果使用WebApplicationContext 并且Bean实现了ServletContextAware接口,调用其setServletContext()方法,仅对web程序有效。

//上述通过实现特有接口,传入给Bean相应的实例,以便使用。

11.如果关联了BeanPostProcessor,调用BeanPostProcessor的postProcessBeforeInitialization()方法。

12.如果Bean实现了InitializingBean接口,调用其afterPropertiesSet()方法执行一些初始化工作。

该初始化工作会发生在XML配置文件设置Bean属性之后,即会覆盖依赖注入的值。

13.如果Bean定义了init-method方法,调用这个方法执行一些初始化工作。

该初始化方法也一样。

14.如果关联了BeanPostProcessor,调用BeanPostProcessor的postProcessAfterInitialization()方法。

容器关闭时,会销毁已创建的Bean:

如果Bean实现了DisposableBean接口,调用其destory()方法执行清理资源等工作。

如果Bean定义了destory-method方法,调用这个方法执行资源清理等工作。

以下代码展示了一些XML文件的配置以及接口的使用:

package com.bean;

import org.springframework.beans.factory.InitializingBean;

public class ChineseImpl implements Person,InitializingBean{

private String name;
private int age;
@Override
public void speak() {
// TODO Auto-generated method stub
System.out.println(this.name+"年龄是"+this.age);
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
this.name="afterPropertiesSet";
this.age = 10;
System.out.println("afterPropertiesSet()执行");
}

}
package com.bean;

public class AmericanImpl implements Person {

private String name;
private int age;
@Override
public void speak() {
// TODO Auto-generated method stub
System.out.println(this.name + "年龄:"+this.age);
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void init(){
this.name="init";
this.age=13;
System.out.println("init 执行");
}

}
//配置文件
<bean id="chinese" class="com.bean.ChineseImpl">
<property name="name" value="小明"></property>
<property name="age" value="23"></property>
</bean>
<!-- init-method指定无参数的初始化方法(通过实现InitializingBean接口,Spring容器会自动调用afterPropertiesSet()方法执行初始化 -->
<bean id="american" class="com.bean.AmericanImpl" init-method="init">
<property name="name" value="托尼"></property>
<property name="age" value="24"></property>
</bean>

//运行
package com.test;

import javax.swing.plaf.basic.BasicIconFactory;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.context.support.XmlWebApplicationContext;

import com.bean.AmericanImpl;
import com.bean.Person;

public class Test {

public static void main(String[] args) {
// TODO Auto-generated method stub
//ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//context = new FileSystemXmlApplicationContext("");
//context = new XmlWebApplicationContext();
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
Person person = (Person)bf.getBean("chinese");
person.speak();
person= (AmericanImpl) bf.getBean("american");
person.speak();

}

}

//运行结果:
afterPropertiesSet()执行
afterPropertiesSet年龄是10
init 执行
init年龄:13


4 装配Bean

4.1 注入基本类型

如上代码所示

4.2 注入引用类型

//新增Book类
package com.bean;

public class Book {

private String bookName;
private String author;
public String getBookName() {
return bookName;
}
public String getAuthor() {
return author;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public void setAuthor(String author) {
this.author = author;
}

}
//在AmericanImpl类中添加下列代码
private Book book;
public void setBook(Book book){
this.book = book;
}
//修改配置文件的部分Bean
<bean id="american" class="com.bean.AmericanImpl" init-method="init">
<property name="name" value="托尼"></property>
<property name="age" value="24"></property>
<property name="book" ref="book"></property>
</bean>
<bean id="book" class="com.bean.Book">
<property name="bookName"><value>书名</value></property>
</bean>


4.3 注入null

//修改配置文件的部分Bean配置
<bean id="american" class="com.bean.AmericanImpl" init-method="init">
<property name="name" value="托尼"></property>
<property name="age" value="24"></property>
<property name="book" ><null></null></property>
</bean>


4.4 注入集合类型

//配置如下,其它集合类似(可以混合使用<value>或<ref>节点),必须和集合或数组的类型相符。
<property name="book" >
<list>
<value></value>
<ref></ref>
</list>
</property>


在使用上诉集合类型时,要注意注入属性的参数使用接口而非具体类,列如,使用List而非ArrayList,这样才能保证Spring能正确地注入,这也符合针对抽象编程的原则。

public void setXxx(List Xxx){} //可以引入泛型,Spring会做强制的转型


4.5 注入Resource资源

除了基本类型、引用类型和集合类型之外,在应用程序中还经常使用各种资源。Java的标准库提供了File、URL、InputStream等常用的资源类型,但是这些资源无法方便地注入到Bean中,因此,Spring提供了一个更强大,更方便的访问底层资源的Resource抽象接口,大大简化了在Bean中注入各种Resource。

在Spring 的配置文件中,注入的Resou
d0de
rce资源总是由一个字符串来表示的,我们无需关心底层的Resource究竟是何种具体类型。事实上,Spring根据字符串来判断应该如何创建相应的Resource。

从字符串到Resource的转化规则:

前缀说明示例
classpath:从ClassPath加载该资源classpath:config.xml
http:作为URL加载该资源http://java.sun.com/
file:作为URL加载该文件资源file:///c:/WINDOWS/
根据具体的ApplicationContexttext.txt

5 构造方法注入

构造方法的参数是强制注入的,相比属性注入,这样可以保证Bean在创建时被正确地初始化了。属性可能由于多次注入而导致不正确的状态。

public AmericanImpl(String name,int age){
this.name=name;
this.age = age;
}
<bean id="am" class="com.bean.AmericanImpl">
<constructor-arg value="constructor"> </constructor-arg>
<constructor-arg value="5"></constructor-arg>
</bean>
//如果有class="com.bean.AmericanImpl"的其它Bean打算采取设置注入,应再写一个默认的构造函数
//public AmericanImpl(){}


6 Bean的作用域

Bean的作用域定义了Bean的生命周期,通过配置文件的智能提醒(scope=”“)可以看到,一共定义了4种作用域:prototype、request、session和singleton。如果不指定scope,默认值是scope=”singleton”。

6.1 Singleton 作用域

Spring的容器仅为每个Bean创建一个实例并保持Bean的引用,意思是,每次调用getBean()方法请求某一个Bean时,Spring总是返回相同的Bean实例。因此,每个Bean有且仅有一个实例。

6.2 prototype 作用域

每次返回Bean的新实例。因此,Spring容器一旦将实例交给客户端,就不再对其跟踪引用,所以无法对prototype作用域的Bean定义destory-method。

7 配置工厂Bean

当我们使用Spring的IoC容器管理Bean时,Spring容器就相当于一个复杂的工厂,它负责根据XML配置文件创建并配置Bean。很多时候,我们需要使用自己的工 厂对象来创建Bean,如果将这一功能也交给Spring容器,Spring管理的就不是普通的Bean实例,而是”工厂“实例。我们把Spring管理的”工厂“实例暂且称为”工厂Bean“。此时,应用程序调用getBean()方法时,Spring返回的不是直接创建的Bean的实例,而是工厂Bean创建的Bean实例。

在Spirng中,可以定义三种不同类型的工厂Bean。下面分别讲解3种工厂Bean的配置。

7.1 使用静态工厂

对象的创建被委托给工厂类的一个静态方法:

public class StaticFactoryBean{
public static Integer createRandom(){
return new Integer(new Random().nextInt());
}
}


如果直接使用这个静态工厂,典型的Java代码:

Integer rnd = StaticFactoryBean.createRandom();


如果将其纳入Spring容器来管理,需要通过factory-method指定静态方法名称。

<bean id="random" class="com.bean.StaticFactoryBean" factory-method="createRandom">
</bean>


调用getBean(“random”)返回的便是静态工厂方法产生的随机数。(若需要每次返回不同的随机数,指定scope=”prototype”即可)

7.2 使用实例工厂

通过实例工厂创建一个对象时,必须首先实例化工厂对象,然后才能调用工厂对象的成员方法,这往往是因为对象的创建还依赖于工厂实例的内部状态。

public class InstanceFactoryBean{
private String format="yy-MM-dd HH:mm:ss";
public void setFormat(String format){
this.format = format;
}
public  String createTime(){
return new SimpleDateFormat(format).format(new Date());
}
}


定义实例工厂需要分别定义两个Bean。

<bean id="instanceFactoryBean" calss="com.action.InstanceFactoryBean">
<property name="format" value="yyyy-MM-dd HH:mm:ss" />
</bean>
<bean id ="currentTime" factory-bean="instanceFactoryBean" factory-method="createTime"></bean>


7.3 实现FactoryBean接口

隐式地使用一个工厂Bean实例,该Bean实现了Spring专有的org.springframework.beans.factory.FactoryBean接口。

package com.bean;

import org.springframework.beans.factory.FactoryBean;
public class AmericanImpl implements Person,FactoryBean<Book> {
@Override
public Book getObject() throws Exception {
// TODO Auto-generated method stub
return new Book();
}
@Override
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return Book.class;
}
@Override
public boolean isSingleton() {
// TODO Auto-generated method stub
return false;
}
}
//定义这个Bean和普通的Bean没有区别:
<bean id="bo" class="com.action.AmericanImpl" />


然而,一旦某个Bean实现了FactoryBean接口,这个Bean就不能再被作为普通Bean使用。Spring的IoC容器会自动地检测,调用getBean(“bo”)返回的将不是AmericanImpl的实例,而是它的工厂方法getObject()返回的Book对象实例。

要获得AmericanImpl的实例,可以用getBean(“&bo”)返回的便是工厂实例。

‘&’符号只能用于实现了FactoryBean接口的工厂Bean。

7.4 常用的FactoryBean

JndiObjectFactoryBean

JndiObjectFactoryBean用于获取指定的JNDI对象,唯一需要指定的是jndiName属性。


<bean id=systemStartTime" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/systemStartTime" />
</bean>

public class Test {

public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
bindJndi();
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println(context.getBean("systemStartTime"));
}
//启动一个基于RMI的JNDI服务并绑定一个Date对象。
private static void bindJndi() throws Exception{
//启动RMI;
LocateRegistry.createRegistry(1099);
//设置JNDI环境
System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
System.setProperty(Context.PROVIDER_URL, "rmi://localhost:1099");
//拓展Date实现Remote接口:
class RemoteDate extends Date implements Remote{}; //使用RMI的JNDI对绑定对象有所限制,被绑定对象必须实现Remote接口
//绑定至JNDI:
InitialContext ctx = new InitialContext();
ctx.bind("java:comp/env/systemStartTime", new RemoteDate());
ctx.close();
}

}

//使用传统的方式去获得一个JNDI对象
private static Object jndiLookup(){
InitialContext ctx = null;

try {
ctx = new InitialContext();
return ctx.lookup("java:comp/env/systemStartTime");
} catch (NamingException e) {
// TODO Auto-generated catch block
throw new RuntimeException();
}finally{
if(ctx!=null)
try {
ctx.close();
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}


通过Spring容器,我们将JNDI的查找简化为几行配置文件。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: