Spring 基础3 —— 配置

Spring 配置文件

Spring 配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<!-- default-lazy-init 属性,指定所有 Bean 默认的延迟初始化行为 -->
<!-- default-merge 属性,指定所有 Bean 默认的 merge 行为 -->
<!-- default-autowire 属性,指定所有 Bean 默认的自动装配行为 -->
<!-- default-autowire-candidates 属性,指定所有 Bean 默认的是否作为自动装配的候选 Bean,可用通配符如:*abc -->
<!-- default-init-method 属性,指定所有 Bean 默认的初始化方法 -->
<!-- default-destory-method 属性,指定所有 Bean 默认的回收方法 -->
<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-4.3.xsd>
    
    <!-- id 属性,该 Bean 唯一标识符,唯一 -->
    <!-- class 属性,该 Bean 具体实现类的全限定类名 -->
    <!-- scope 属性,该 Bean 的作用域 -->
    <!-- autowire 属性,配置自动装配,可选:no / byName / byType / constructor / autodetect -->
    <!-- autowire-candidate 属性,为 false 则该 Bean 限制在自动装配外,容器在查找自动装配时不考虑该 Bean -->    
    <!-- abstract 属性,指定是否为抽象 Bean。抽象 Bean 不能被实例化,通常作为父 Bean 被继承 -->
    <!-- parent 属性,指定父 Bean,子 Bean 可以继承父 Bean 的实现类,构造器参数,属性值。子 Bean 的集合属性值可从父 Bean 的集合属性继承和覆盖(子覆盖父)而来 -->
    <!-- depends-on 属性,指定依赖的 Bean,当 Bean 初始化前会先初始化所依赖的 Bean -->
    <!-- init-method 属性,指定类中某一方法为初始化方法,该方法在初始化并依赖关系设置完成后触发 -->
    <!-- destory-method 属性,指定类中某一方法为销毁方法,该方法在 Bean 销毁之前触发 -->
    <bean id="person" class="com.lian.entity.Person">
        <!-- 通过设值注入方式创建 bean,对应的属性必须有相应的 setter -->
        <!-- name 属性,属性名 -->
        <!-- value 属性,设置属性值 -->
        <!-- ref 属性,另一个 bean 的引用 -->
        <property name="name" value="/WEB-INF/jsp/" />
        
        <!-- 通过构造注入方式创建 bean,对应 bean 必须有相应的构造器 -->
        <!-- 多个 constructor-arg 先后位置分别代表在构造器中传入的参数的顺序 -->
        <!-- index 属性,可指定参数在构造器的位置 -->
        <!-- value 属性,设置属性值 -->
        <!-- ref 属性,另一个 bean 的引用 -->
        <constructor-arg value=""/>
    </bean>
</beans>
  • 一般情况下采用 XML Schema 来定义配置文件的语义约束
  • 在 Schema 中,只有 spring-beans-x.x.xsd 是 Spring 的内核,其他 Schema 大多用于简化某些方面的配置
  • 基于 XML Schema 的简化配置方式
    • p Schema,用于简化属性的配置,不需要定义 Schema,直接存在于 Spring 的内核中
      xmlns:p="http://www.springframework.org/schema/p"
      
    • util Schema
      xmlns:util="http://www.springframework.org/schema/util"
      
      http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd
      
    • aop Schema,用于简化 AOP 的配置
      xmlns:aop="http://www.springframework.org/schema/aop"
      
      http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
      
    • tx Schema,用于简化事务的配置
      xmlns:tx="http://www.springframework.org/schema/tx"
      
      http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
      
    • context Schema
      xmlns:context="http://www.springframework.org/schema/context"
      
      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
      
    • jee Schema,用于简化 JavaEE 的配置
      xmlns:jee="http://www.springframework.org/schema/jee"
      
      http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd
      
    • jms Schema,用于简化 JMS 的配置
      xmlns:jms="http://www.springframework.org/schema/jms"
      
      http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-4.3.xsd
      
    • lang Schema,用于简化动态语言的配置
      xmlns:lang="http://www.springframework.org/schema/lang"
      
      http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-4.3.xsd
      

两种注入方式

设值注入和构造注入

容器中 Bean 的作用域

通过 scope 属性可设置 Bean 的作用域,属性值有:

  • singleton —— 单例,默认
  • prototype —— 每次通过容器获取 Bean 时都产生一个新的 Bean 实例
  • request —— 对每次 HTTP 请求,都产生一个新的 Bean 实例
  • session —— 对每次 HTTP Session ,都产生一个新的 Bean 实例
  • globalSession —— 每个全局的 HTTP Session 对应一个 Bean 实例

对于 request 和 session 作用域,需在 web.xml 中配置 Listener。如果使用 SpringMVC 做 MVC 框架,则不需要

<listener>
    <linstener-class>org.springframework.web.context.request.RequestContextLinstener</linstener-class>
</linstener>

容器中 Bean 的生命周期

  • Spring 可以管理 singleton 作用域的 Bean 的生命周期(何时创建、何时初始化完成、何时准备要销毁)
  • prototype 作用域的 Bean ,Spring 容器仅仅负责创建
  • 管理 Bean 的生命周期行为主要有两个时机:注入依赖关系之后即将销毁 Bean 之前
  • 通过 init-method 属性和 destory-method 属性可指定 注入依赖关系之后 和 即将销毁 Bean 之前 的处理方法
    public class Chinese {
    
        public Chinese() {
            System.out.println("实例化");
        }
        
        public void init() {
            System.out.println("初始化");
        }
        
        public void close() {
            System.out.println("销毁");
        }
    }
    
    <bean id="chinese" class="con.lian.Chinese" init-method="init" destory-method="close"/>
    

协调作用域不同步的 Bean

  • 利用 方法注入 可解决当 singleton 作用域 Bean 依赖 prototype 作用域 Bean 时的不同步现象
  • 方法注入通常使用 lookup 方法注入,利用 lookup 方法注入可以让 Spring 容器重写容器中的 Bean 的抽象或具体方法,返回查找容器中其他 Bean 的结果。Spring 采用 CGLIB 库修改客户端的二进制码,从而实现上述的要求
public class PrototypeBean {

    public String someMethod() {
        return "is someMethod";
    }
}


public class SingletonBean {
    
    // 定义一个抽象方法,方法的返回类型是被依赖的 prototype 作用域 Bean
    // 方法由 Spring 负责实现
    public abstract PrototypeBean getPrototypeBean();
    
    public void usePrototypeBean() {
        System.out.println(getPrototypeBean().someMethod());
    }
}
<bean id="prototypeBean" class="com.lian.PrototypeBean" scope="prototype"/>

<bean id="singletonBean" class="com.lian.SingletonBean">
    <lookup-method name="getPrototypeBean" bean="prototypeBean"/>
</bean>

注入嵌套 Bean

嵌套 Bean 只对它嵌套的外部 Bean 所见

<property name="name">
    <bean class=""/> 
</property>

注入集合类

  • List
    <property name="name">
        <list>
            <!-- 每个 value、ref、bean 都配置一个 list 元素 -->
            <value>aaa</value>
            ...
        </list>
    </property>
    
  • Set
    <property name="name">
        <set>
            <!-- 每个 value、ref、bean 都配置一个 set 元素 -->
            <value>aaa</value>
            <bean class=""/>
            <ref local=""/>
        </set>
    </property>
    
  • Map
    <property name="name">
        <map>
            <!-- 每个 entry 都配置一个 key-value 对 -->
            <!-- key-ref 属性 -->
            <!-- value-ref 属性 -->
            <entry key="" value=""/>                
            <entry key="" value-ref=""/>
        </map>
    </property>
    
  • 数组
    与 List 相同
  • Properties
    <property name="name">
        <props>
            <prop key="身高">174</prop>
        </props>
    </property>
    

组合属性注入

可以使用组合属性的方位,为如 属性.属性 指定值

<property name="person.name" value="hahaha"/>

为组合属性指定值时,除最后一个属性,其他属性都不能为 null

抽象 Bean 与子 Bean

通过 abstract 属性可设置 Bean 是否为抽象 Bean

抽象 Bean 不能被实例化,通常作为父 Bean 被继承,即作为一个 Bean 模板,由子 Bean 继承父 Bean 的实现类、构造器参数、属性值。子 Bean 的集合属性值也可从父 Bean 的集合属性继承和覆盖(子覆盖父)而来

通过 parent 属性,可为 Bean 指定父 Bean

子 Bean 可重新覆盖父 Bean 的配置

<bean id="being" class="com.lian.Being" abstract="true">
    <property name="sex" value="male"/>
</bean>

<bean id="lucy" parent="being">
    <!-- 覆盖父 Bean 中依赖关系的配置 -->
    <property name="sex" value="female"/>
</bean>

强制初始化 Bean

  • Spring 默认先初始化主调 Bean,再初始化依赖 Bean
  • 假设 Bean 之间的依赖关系不够直接,可以使用 depends-on 属性强制初始化 Bean
    <bean id="beanOne" class="com.lian.ExampleBean" depends-on="manager">
        <property name="manager" ref="manager"/>
    </bean>
    
    <bean id="manager" class="ManagerBean"/>
    

注入其他 Bean 的属性值、Field 值、方法返回值(缺)

Bean 实例的创建方式

  • 使用构造器创建 Bean 实例
    // 创建 ApplicationContext 实例
    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    // 调用 Person 默认构造器创建实例
    // 根据配置文件注入依赖关系
    // 返回 Chinese 实例
    Person p = ctx.getBean("chinese", Person.class);
    
  • 使用静态工厂方法创建 Bean 实例
    public interface Being {
        public void doSomething();
    }
    
    public class Person implements Being {
        private String name;
        // getter setter
        ...
    
        public void doSomething() {
            ...
        }
    }
    
    public class BeingFactory {
        public static Being getBeing(String str) {
            if (str.equals("person")) {
                return new Person();
            }
        }
    }
    
    <!-- class 属性为静态工厂类 -->
    <!-- factory-method 属性指定静态工厂方法 -->
    <bean id="person" class="xxx.BeingFactory" factory-method="getBeing">
        <!-- 配置静态工厂方法的参数 -->
        <constructor-arg value="person"/>
        <!-- 配置普通依赖属性 -->
        <property name="name" value="haha"/>
    </bean>
    
    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    
    Being b = ctx.getBean("person", Being.class);
    
  • 调用实例工厂方法创建 Bean 实例
    public interface Being {
        public void doSomething();
    }
    public class Person implements Being {    
        public void doSomething() {
            ...
        }
    }
    public class BeingFactory {
        public Being getBeing(String str) {
            if (str.equals("person")) {
                return new Person();
            }
        }
    }
    
    <bean id="beingFactory" class="xxx.BeingFactory"/>
    <!-- 无须 class 属性,因为 Spring 不再直接实例化该 Bean -->
    <!-- factory-bean 属性,工厂 Bean 的 id -->
    <!-- factory-method 属性,实例工厂的工厂方法 -->
    <bean id="person" factory-bean="beingFactory" factory-method="getBeing">
        <!-- 配置静态工厂方法的参数 -->
        <constructor-arg value="person"/>
    </bean>
    

容器中的工厂 Bean

  • 工厂 Bean 是 Spring 的一种特殊 Bean ,必须实现 FactoryBean 接口
  • 当通过 getBean() 方法来获取工厂 Bean 时,容器返回的是工厂 Bean 的产品
public class PersonFactory implements FactoryBean<Person> {
    Being p = null;
    // 实现该方法负责返回该工厂 Bean 生成的实例
    public Being getObject() {
        if (p == null) {
            p = new Person();
        }
        return p;
    }
    // 实现该方法返回该工厂 Bean 生成实例的实现类
    public class<? extends Being> getObjectType() {
        return Person.class;
    }
    // 实现该方法表示该工厂 Bean 生成的实例是否为单例模式
    public boolean isSingleton() {
        return true;
    }
}
<bean id="person" class="xxx.PersonFactory"/>
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

Being b = ctx.getBean("person", Being.class);

Annotation 方式配置 Spring

在 Spring 配置文件中指定搜索路径(context Schema)

<context-component-scan bask-package="xxx.xxx">
    <context:include-filter type="" expression=""/>
    <context:exclude-filter type="" expression=""/>
</context-component-scan>
  • 搜索 Bean
    • @Component("xxx") —— 括号指定 id ,默认为首字母小写的类名
    • @Controller
    • @Service
    • @Repository
  • 指定 Bean 的作用域
    • @Scope("xxx") —— 括号为作用域的名称
  • 配置依赖
    • @Resource(name="") —— name 指定需要注入的实例的名字
      可用于修饰 Field 或者 setter 方法
  • 指定生命周期行为
    • @PostConstruct —— 即 init-method
    • @PreDestory —— 即 desotry-method
  • 强制初始化其他 Bean
    • @DependOn({"", ""}) —— 字符串数组指定需要强制初始化其他 Bean 的 id
  • 取消预初始化
    • @Lazy(boolean) —— 是否要预初始化 Bean
  • 自动装配和精确装配
    • @Autowired
    • @Qualifier
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,869评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,716评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,223评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,047评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,089评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,839评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,516评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,410评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,920评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,052评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,179评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,868评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,522评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,070评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,186评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,487评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,162评论 2 356

推荐阅读更多精彩内容