Spring-IOC/DI-1



一. Spring基础

1. Eclipse安装

准备工作:
1. Spring插件
2. Spring jar包

2. 安装过程

help –> install new software –> add –> archive –> 找到本地spring插件
—> 只点击后缀带有spring IDE的项 —> 联网更新去掉 —> eclipse重启

3. 导入jar包

把一下jar包加入到工程的classpath当中

  1. commons-logging-1.1.1.jar–>spring必须依赖的日志包
  2. beans
  3. context
  4. core
  5. expression

4. Spring HelloWorld程序

  1. 新建Java project spring-1
  2. 新建lib–>导入jar包–>bulid to path

4.1 HelloWorld类

package com.mozart.beans;

public class HelloWorld{

    private String name;

    public void setName(String name){
        this.name=name;
    }

    public void hello(){
        System.out.println("hello: "+name);
    }
}

4.2 不使用Spring的测试代码

package com.mozart.beans;

public class Main{
    public static void main(String[] args){
        /1./创建HelloWorld对象
        HelloWorld helloWorld=new HelloWorld();

        //2.为name属性赋值
        helloWorld.setName("mozart");

        //3.调用方法
        helloWorld.hello();
    }
}

运行结果:

hello: mozart

4.3 配置xml文件

src下创建一个Spring Bean configuration File–>applicationContext.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans"
>>
    <bean id="helloWorld" class="com.atguigu.spring.beans.helloWorld">
        <propertiy name="name2" value="Spring"></propertiy>>
    </bean>>
</beans>>

4.4 使用Spring的HelloWorld程序

package com.mozart.beans;

public class Main{
    public static void main(String[] args){
         //1.创建Spring的IOC容器对象
         ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");

         //2.从IOC容器当中获取Bean实例
         HelloWorld helloWorld=(HelloWorld) ctx.getBean("helloWorld");

         //3.调用方法
         helloWorld.hello();
    }
}

个人理解
1. ApplicationContext就代表IOC容器,它是一个接口。
2. ClassPathXmlApplicationContext: 表示配置文件在类路径下.

创建IOC容器
1. 会对配置文件当中配置的Bean进行初始化
2. 同时会对属性进行复制

二. Spring原理——IOC和DI

1. 名词解释

IOC(Inversion of control)—->反转控制
1. 传统的资源查找方式:组件向容器发起请求查找资源。
2. IOC: 容器主动地将资源推送给管理的组件。

DI(Dependency Injection)—->依赖注入(和反转控制是一个意思)


2. 举例理解

需求: 容器中有两个类A和B。B中有个属性a依赖A。
要求获取B对象。

传统的方式:

A a=getA();
B b=getB();
b.setA(a);

IOC容器的方式:
容器自动把关联关系建立好了。

3. IOC的前生

  1. 分离接口与实现
  2. 工厂模式
  3. 采用反转控制

举例一个需求:
ReportService类要用到报表生成器ReportGenerator的接口。
ReportGenerator的接口有两个实现类PDFReportGenerator实现类
HtmlReportGenerator实现类

1. 分离接口与实现

缺点: 耦合性太高

spring-1

2. 工厂模式

缺点: 代码实现复杂

spring-2

3. IOC容器

自动化方式,stay foolish!

spring-3


三. Spring Bean的配置

1. Bean配置简介

1.1 Bean的配置形式

  1. 基于xml配置文件的方式
  2. 基于注解的方式

1.2 Bean的配置方式

  1. 通过全类名(反射)
  2. 通过工厂方法(静态工厂方法&实例工厂方法)
  3. FactoryBean

1.3 IOC容器

  1. BeanFactory
  2. ApplicationContext

1.4 依赖注入的方式

  1. 属性注入
  2. 构造器注入

2. IOC容器

SpringIOC容器读取Bean配置,创建Bean之前,必须要对IOC容器进行初始化。只有对IOC容器初始化实例化完成了,
才能够从IOC容器当中获取Bean实例并使用。

Spring提供了两种类型的IOC容器的实现方式:

  1. BeanFactory: Spring框架的基本设施,IOC容器的基本实现。

  2. ApplicationContext 提供了更多高级特性,是BeanFactory的子接口。几乎所有的场合都使用ApplicationContext而不是BeanFactory.

  3. ConfigurableApplicationContextApplicationContext的子接口。ConfigurableApplicationContext中有新的功能,比如refresh(),close()。让容器具有启动,刷新,关闭的功能。

  4. ConfigurableApplicationContext有两个主要的实现类
    ClassPathXmlApplicationContext:从类路径下加载配置文件
    FileSystemXmlApplicationContext: 从文件系统当中加载配置文件。

ApplicationContext在初始化的时候就实现了所有单例的Bean
非单例Bean将在Bean的作用域的时候再说。

WebApplicationContext是专门为Web应用而准备的。

3. 通过IOC容器获取Bean

BeanFactory当中具有获取Bean的方法。
ListableBeanFactory是继承了BeanFactory
ApplicationContext是实现了ListableBeanFactory
所以,ApplicationContext也具有了获取Bean的方法。

通过ID: ID能够唯一定位Bean

new ClassPathXmlApplicationContext("applicationContext.xml").getBean("Bean的id");

通过类型class: 不能唯一定位,使用它要求Bean在容器中是唯一的。

new ClassPathXmlApplicationContext("applicationContext.xml").getBean(HelloWorld.class)

4. Bean的xml配置

id: 通过id来应用Bean,id必须是唯一的。

class: Bean的全类名,通过反射的方式在IOC容器当中创建Bean的实例,要求Bean当中有无参构造器

4.1 属性的依赖注入的方式

Spring支持3种依赖注入的方式

1.属性注入: 通过setter方法为Bean的属性注入值或者注入引用,开发当中最常用

<property name="name" value="Spring"></property>

2.构造器注入: 不提供setter方法,通过构造器初始化的操作进行类中属性赋值。

没有name属性

    <constructor-arg value="Audi" index="0"></constructor-arg>
    <constructor-arg value="Shanghai" index="1"></constructor-arg>
    <constructor-arg value="300000" index="2"></constructor-arg>

这样写很容易产生歧义的。可能很多赋值都匹配一个构造器的。
解决方法如下:

<constructor-arg value="Audi" type="java.lang.String"></constructor-arg>
<constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg>
<constructor-arg value="300000" type="double"></constructor-arg>
<constructor-arg type="int">
    <value>250</value>
</constructor-arg>

属性值可以用value属性也可以使用value子节点进行赋值.

4.2 字面值注入

value表示的字面值

字面值: 可以用字符串表示的值,可以通过元素标签或者value属性进行注入。
基本数据类型及其封装类,String类型都可以采用字面值注入的方式进行注入。
若字面值当中包含一些特殊字符的话,可以使用<![CDATA[]]>把字面值包裹起来。

如下:

<constructor-arg index="1">
    <value><!CDATA[<Shanghai^>]></value>
</constructor-arg>

4.3 Bean之间的引用配置

<bean id="person" class="com.atguigu.spring.beans.Person">
    <property name="name" value="tom"></property>
    <property name="age" value="tom"></property>
    <!--可以使用property的ref属性建立bean之间的引用关系-->
    <property name="car" ref="car2"></property>

    <property name="car">
        <ref bean="car2" />
    </property>
</bean>

组成应用程序的Bean需要相互协助.
在Bean的配置文件当中,可以通过元素或者ref属性为Bean的属性或者构造器参数指定对Bean的引用。
也可以在属性或者构造器的内部包含一个bean的声明,这样的Bean称之为内部Bean。

4.4 内部Bean

<bean id="person" class="com.atguigu.spring.beans.Person">
    <property name="name" value="tom"></property>
    <property name="age" value="20"></property>
    <!--可以使用property的ref属性建立bean之间的引用关系-->
    <property name="car" ref="car2"></property>

    <property name="car">
        <bean class="com.atguigu.spring.beans.Car">
            <contructor-arg value="Ford"></contructor-arg>    
            <contructor-arg value="Changan"></contructor-arg>    
            <contructor-arg value="200000" type="double"></contructor-arg>    
        </bean>
    </property>
</bean>

内部Bean不用写id,不能够被外部引用的。

<bean id="person2" class="com.atguigu.spring.beans.Person">
    <contructor-arg value="jerry"></contructor-arg>
    <contructor-arg value="25"></contructor-arg>
    <contructor-arg ref="car2"></contructor-arg>
</bean>

4.5 注入参数详解—null值和级联属性

可以使用专用的<null/>元素标签为Bean的字符串或者其他对象类型的属性赋值为null值。
其实没有多大的意思,因为引用类型的默认都是null。

<bean id="person2" class="com.atguigu.spring.beans.Person">
    <contructor-arg value="jerry"></contructor-arg>
    <contructor-arg value="25"></contructor-arg>
    <contructor-arg><null/></contructor-arg>
</bean>

Spring支持级联属性的配置。(Bean当中的Bean的属性赋值)

注意,属性需要先初始化后,才可以为级联属性赋值。否则异常,和Struts2不同。

<bean id="person2" class="com.atguigu.spring.beans.Person">
    <contructor-arg value="jerry"></contructor-arg>
    <contructor-arg value="25"></contructor-arg>
    <contructor-arg ref="car"></contructor-arg>
    <!--为级联属性赋值,这要求car这个类当中有setPrice方法-->
    <property name="car.price" value="300000"></property>
</bean>

4.6 集合属性

一个人可以有好多辆车,人对象,车对象,怎么在xml当中配置bean。

使用节点为list的属性赋值

<list> <set> <map>标签配置集合属性。

<bean id="person2" class="com.atguigu.spring.beans.Person">
<property name="name" value="Mike"></property>
<property name="age" value="27"></property>
<property name="cars">
    <list>
        <ref bean="car" />
        <ref bean="car2" />
    </list>
</property>
</bean>

4.7 配置map属性值

使用map节点以及mapentry子节点配置map类型的成员变量。

<bean id="person2" class="com.atguigu.spring.beans.Person">
<property name="name" value="Mike"></property>
<property name="age" value="27"></property>
<property name="cars">
    <map>
        <entry key="AA" value-ref="car"></entry>
        <entry key="BB" value-ref="car2"></entry>
    </map>
</property>
</bean>

4.8 Properties

PropertiesHashTable的一个子类,HashTableMap的一个实现类.
到时候和hibernate可以整合。
使用propsprop子节点来为properties属性赋值.

<bean id="datasource" class="com.atguigu.spring.beans.collection.datasource">
    <property name="properties">
        <props>
            <prop key="user">root</prop>
            <prop key="password">1234</prop>
            <prop key="jdbcurl">jdbc:mysql:///test</prop>
            <prop key="driverClass">com.mysql.jdbc.Driver</prop>
        </props>
    </property>
</bean>

4.9 使用utility schema定义集合

配置单例的集合Bean,以供多个Bean进行引用
引入新的util命名空间。

<util:list id="cars">
    <ref bean="car" />
    <ref bean="car2" />
</util:list>

<bean id="person4" class="com.atguigu.spring.beans.collection.Person">
<property name="name" value="Jack"></property>
<property name="age" value="29"></property>
<property name="cars" ref="cars"></property>
</bean>

4.10 使用p命名空间

Spring2.5当中引入了新的命名空间,可以通过比较简化的方式配置bean属性。
需要先导入p命名空间。
相对于传统的配置方式,更加简洁。

<bean id="person5" class="com.atguigu.spring.beans.collection.Person"
    p:name="Queen" p:age="30" p:car-ref="cars"
></bean>

4.11 自动装配

Spring IOC容器可以自动装配Bean,需要做的就是仅仅是在<bean>autowire属性当中指定自动装配的模式。

byType(根据类型自动装配):
若IOC容器中有多个与目标Bean类型一致的Bean
在这种情况下,Spring将无法判定哪个Bean最合适该属性
,所以不能执行自动装配。

byName(根据名称自动装配):
必须将目标Bean的名称和属性设置的完全相同。

constructor(通过构造器自动装配):
Bean中存在多个构造器的时候,此种装配方式将会很复杂,不推荐使用.

举例说明
person对象有name,address对象(city,street),car对象(brand,price)

beansautowire.xml代码

<bean id="address" class="com.atguigu.spring.beans.autowire.Address"
    p:city="beijing"
    p:street="HuiLongGuan"
>
</bean>

<bean id="car" class="com.atguigu.spring.beans.autowire.Car"
    p:brand="Audi"
    p:price="300000"
>
</bean>

<bean id="person" class="com.atguigu.spring.beans.autowire.person"
    p:name="Tom"
    p:address-ref="address"
    p:car-ref="car"
>

<bean id="person" class="com.atguigu.spring.beans.autowire.person"
    p:name="Tom" autowire="byType"
>
</bean>

byName:根据bean的名字和当前beansetter方法的属性名进行自动装配,
若有匹配的,则进行自动装配,若没有匹配的,则不进行装配。

byType 根据Bean的类型和当前bean的属性的类型进行自动装配,若IOC容器当中有1个以上的类型匹配的bean,则抛出异常。

在Bean配置文件里设置autowire属性进行自动装配将会装配Bean的所有属性,
然而,若只希望装配个别属性的时候,autowire属性就不够灵活了。

autowire属性要么根据类型自动装配,要么根据名称自动装配,不能两者兼而有之。

一般情况下,在实际的项目中很少使用自动装配功能,因为和自动装配功能所带来的好处比起来,明确清晰的配置文档更有说服力一些。

但是在整合第三方框架的时候会使用autowire,会给我们带来一些方便。

4.12 bean之间的关系:继承/依赖

Spring允许继承bean的配置,被继承的bean称之为父bean,继承这个父beanbean称之为子bean

bean从父bean中继承配置,包括bean的属性配置
bean可以覆盖从父bean当中继承过来的配置。

bean可以作为配置模板,也可以作为bean实例,若只想把父bean作为模板,可以设置<bean>abstract属性为true,这样spring将不会实例化这个bean

并不是bean元素里头的所有的属性都会被继承,比如 autowire,abstract等。

也可以忽略父beanclass属性,让子bean指定自己的类,而共享相同的属性配置,
但此时abstract必须设为true

如果把beanclass属性去掉,就必须加上abstract=true

<bean id="address" class="com.atguigu.spring.beans.autowire.address"
p:city="Beijing" p:street="WuDaoKou" abstract="true"></bean>

<bean id="address2"  p:street="DaZhongSi" parent="address"></bean>

<bean id="person" class="com.atguigu.spring.beans.autowire.person"
    p:name="Tom" p:address-ref="address2" depends-on="car">
</bean>

Spring允许用户通过depends-on属性设定bean前置依赖的bean
前置依赖的bean会在本bean实例化之前创建好。
如果前置依赖于多个bean,则可以通过都好,空格或的方式配置bean的名称。

4.13 配置Bean的作用域

使用Beanscope属性来配置bean的作用域
singleton: 默认值,容器初始时创建bean实例,在整个容器的生命周期内只创建了这一个bean,是单例的。
prototype:原型的,容器初始化的时候并没有创建bean实例,你请求bean的时候,容器就创建一个bean,再请求再创建,是不一样的bean实例.

<bean id="Car" class="com.atguigu.spring.bean.beanscope" scope="singleton">
<property name="brand" value="Audi"></property>
<property name="price" value="200000"></property>
</bean>

4.14 使用外部属性文件

在配置文件里配置bean的时候,有时候需要在bean的配置里混入系统部署的细节信息(例如:文件路径,数据源配置信息等)
而这些部署细节实际上需要和bean的配置相分离。

Spring提供了一个PropertyPlaceholderConfigurerBeanFactory后置处理器

这个处理器允许用户将bean配置的部分内容外移到属性文件当中。
可以在bean配置文件里头使用形式为${var}的变量

PropertyPlaceholderConfigurer从属性文件里头加载属性,
并使用这些属性来替换变量。

Spring还允许在属性文件里头使用$(propName),以实现属性之间的相互作用。

bean-property.xml配置一个数据源
导入c3p0-0.9.1.2.jar
加入mysql的驱动mysql-connector-java-5.1.7-bin.jar

<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="user" value="root"></property>
    <property name="password" value="1230"></property>
    <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
    <property name="jdbcUrl" value="jdbc:mysql:///test"></property>
</bean>
<!-- 导入属性文件 -->
<context:property-placeholder location="classpath:db.properties" />

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="user" value="$(user)"></property>
    <property name="password" value="$(password)"></property>
    <property name="driverClass" value="$(driverClass)"></property>
    <property name="jdbcUrl" value="$(jdbcUrl)"></property>
</bean>

5. Spring表达式语言 :SpEL

5.1 SpEL简介

Spring表达式语言(简称SpEL):
是一个支持运行时查询和操作对象的强大的表达式语言

语法类似于EL: SpEL使用#{}作为定界符,所有在大括号里头的字符都被认为是SpEL

SpELbean的属性进行动态赋值提供了便利。

通过SpEL可以实现:

  1. 通过beanidbean进行引用
  2. 调用方法以及引用对象中的属性
  3. 计算表达式的值
  4. 正则表达式的匹配

5.2 SpEL字面量

字面量的表示:
整数: <property name="count" value="#{5}"></property>
小数: <property name="count" value="#{89.7}"></property>
科学计数法: <property name="count" value="#{1e4}"></property>
字符串: <property name="count" value="#{'chuck'}"></property>
布尔值: <property name="count" value="#{false}"></property>

如果是仅仅是赋字面值的话用SpEL的意义不大的。

5.3 引用其他对象

<property name="prefix" value="#{prefixGenerator}"></property>

相当于

<property name="prefix" ref="prefixGenerator"></property>

5.4 引用其他对象的属性

<property name="prefix" value="#{prefixGenerator.suffix}"></property>

调用其他方法,还可以链式操作(动态为属性进行赋值)

<property name="prefix" value="#{prefixGenerator.toString()}"></property>
<property name="prefix" value="#{prefixGenerator.toString().toUpperCase()}"></property>

5.5 运算符

算数运算符:+ - * / %, 加号可以作为字符串的连接符
比较运算符:< > == <= >= lt gt eq le ge
逻辑运算符: and or not
if-else运算符: ?():()
正则表达式:matches

5.6 调用静态方法或静态属性: T()

<property name="prefix" value="#{T(java.lang.Math).PI}"></property>
<bean id="address" class="com.atguigu.spring.beans.spel.Address">
    <property name="city" value="#{'Beijing'}"></property>
    <property name="street" value="Wudaokou"></property>
</bean> 

6. IOC容器中Bean的生命周期

SpringIOC容器可以管理Bean的生命周期,Sprirng允许在Bean生命周期的特定点执行定制的任务。

6.1 Bean的生命周期管理过程

SpringIOC容器对Bean的生命周期进行管理的过程:

  • 通过构造器或工厂方法创建bean实例。
  • 为bean的属性设置值和对其他bean的引用
  • 调用用bean的初始化方法
  • bean可以使用了
  • 当容器关闭时,调用bean的销毁方法

在bean的生命里设置init-methoddestroy-method属性,为bean指定初始化和销毁方法。

<bean id="car" class="com.atguigu.spring.beans.cycle.Car" init-method="init" destroy-method="destroy">
    <property name="brand" value="Audi"></property>
</bean>

6.2 创建bean后置处理器

bean后置处理器允许在调用初始化方法前后对Bean进行额外的处理。

bean后置处理器对IOC容器里的所有bean实例注意处理,
而非是单一实例。

其典型应用是:检查bean属性的正确性或根据特定的标准更改bean的属性。

对bena后置处理器而言,需要实现interface beanPostProcessor接口。

在初始化方法被调用前后,Spring将把每个bean实例分别传递给上述接口的以下两个方法:

postProcessAfterInitialization(Object bean,String beanName);
postProcessBeforInitialization(Object bean,String beanName);

Spring IOC容器对bean的生命周期进行管理的过程 :

  1. 通过构造器或工厂方法创建bean实例。
  2. 为bean的属性设置值和对其他bean的引用
  3. 将bean实例传递给Bean后置处理器的postPorcessBeforInitialization方法
  4. 调用bean的初始化方法
  5. 将bean实例传递给Bean后置处理器的postPorcessAfterInitialization方法
  6. bean可以使用了
  7. 当容器关闭的时候,调用bean的销毁方法

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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="car" class="com.atguigu.spring.beans.cycle.Car" init-method="init" destroy-method="destroy">
    <property name="brand" value="Audi"></property>
</bean>

<!-- 配置bean的后置处理器 -->
<bean class="com.atguigu.spring.beans.cycle.MyBeanPostProcessor"></bean>

</beans>

后置处理器类代码

package com.atguigu.spring.beans.cycle;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcessor implements BeanPostProcessor {

    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        System.out.println("postProcessBeforeInitialization" + bean + "," + beanName);
        //可以检查bean,这是通用的。
        //可以创建一个新的bean,然后返回
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        System.out.println("postProcessAfterInitialization" + bean + "," + beanName);
        return null;
    }


}

后置处理器类代码

public class MyBeanPostProcessor implements BeanPostProcessor {

    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        System.out.println("postProcessBeforeInitialization" + bean + "," + beanName);
        //可以检查bean,这是通用的。
        //可以创建一个新的bean,然后返回
        if("car".equals(beanName)){
            //....对bean进行过滤
        }
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        System.out.println("postProcessAfterInitialization" + bean + "," + beanName);
        Car car=new Car();
        car.setBrand("Ford");
        return car;
    }
}

7. 通过工厂方法(静态工厂方法和实例工厂方法)配置bean

上面都是通过全类名反射配置bean

7.1 静态工厂方法

直接调用某一个类的静态方法就可以返回bean的实例

工厂类代码

public class StaticFactory{
    private static Map<String,car> cars=new HashMap<String,Car>();

    static{
        cars.put("audi",new Car("audi",300000));
        cars.put("ford",new Car("ford",400000));
    } 

    //静态工厂方法
    public static Car getCar(String name){
        return cars.get(name);
    }
}

xml配置代码

    <!--通过静态工厂方法来配置bean,不是配置静态工厂方法实例,而是配置bean实例-->
    <!--class属性指向静态工厂方法的全类名,factory-mehod指向静态工厂方法的方法名字
    如果工厂方法需要传入参数,则使用constructor-arg来传递参数
    -->
<bean id="car1" class="com.lingyao.StaticFactory" factory-method="getCar">
    <constructor-arg value="audi"></constructor-arg>
</bean>

7.2 实例工厂方法

实例工厂的方法,也就是先创建工厂本身,再调用工厂的实例方法。

工厂类代码

public class InstanceCarFactory{
    private Map<String,Car> cars=null;

    public InstanceCarFactory(){
        cars=new HashMap<String,Car>();
        cars.put("audi",new Car("audi",300000));
        cars.put("ford",new Car("ford",400000));
    }

    public Car getCar(String name){
        return cars.get(name);
    }
}

xml配置代码

<bean id="car1" class="com.lingyao.StaticFactory" factory-method="getCar">
    <constructor-arg value="audi"></constructor-arg>
</bean>

8. FactoryBean配置方式

为什么要用FactoryBean?
配置bean的时候要用到IOC容器的其他bean,用factoryBean是最合适。

自定义FactoryBean需要实现Spring当中的一个接口叫做:FactoryBean

public class CarFactoryBean implements FactoryBean<Car>{
    //返回bean的对象
    private Stirng brand;

    public void setBrand(String brand){
        this.brand=brand
    }

    public Car getObejct() throws Exception{
        return new Car("BMW",500000);
    }

    //返回bean的类型
    public Class<?> getObjectType(){
        return  Car.class;
    }

    public boolean isSingleton(){
        return true;
    }
}

通过FactoryBean配置bean实例,class执行FactoryBean的全类名
property是FactoryBean的属性
但返回的实例就是FactoryBean中的getObject方法返回的一个bean

<bean id="car" class="com.lingyao.CarFactoryBean" factory-method="getCar">
<property name="brand" value="BMW"></property>
</bean>

9. 基于注解的方式配置bean

上面所有的配置bean的方式都是基于xml文件的方式进行配置的。
1. 基于注解配置bean
2. 基于注解配置bean的属性

9.1 在classpath中扫描组件

组件扫描(component scanning):Spring能够从classpath下自动扫描,侦测和实例化具有。特定注解的组件。

特定组件包括:
@Component: 基本注解,标识了一个受Spring管理的组件。
@Respository: 标识持久层组件
@Service: 标识服务层(业务层)组件
@Controller: 标识表现层组件

对于扫描到的组件,Spring有默认的命名策略:
使用非限定类名,第一个字母小写.
也可以在注解中通过value属性值标识组件的名称。

当在组件类上使用了特定的注解之后,
还需要在Spring的配置文件中声明
<context:componext-scan>

base-package属性指定一个需要扫描的基类包,
Spring容器将会扫描这个基类包里及其子包中的所有类。

当需要扫描多个包时,可以使用逗号分隔。

如果仅希望扫描特定的类而非基包下的所有类,
可以使用resource-pattern属性过滤特定的类,示例:

<context:component-scan
    base-package="com.atguigu.spring.beans"
    resource-pattern="autowire/*.class" />
<context:include-filter> 子节点表示要包含的目标类
<context:exclude-filter> 子节点表示要排除在外的目标类
<context:component-scan> 下可以拥有若干个<comtext:include-filter>
和<context:exclude-filter>子节点。

比方说有很多包,包中所有的类都用注解标识上了,然后配置了context:component-scan,就指定扫描那些包。

举例理解:
第一, 建立一个TestObject类,加上注解@
第二, 接口UserRepository
实现类 UserRepositoryImple implements UserRepostory
注解@Repository,模拟持久化层

第三: UserService类,其中有个方法add(){}方法
注解:@Service

第四: UerController类,其中有个execute(){}方法,
注解@Controller.

创建bean的配置文件—->beans-annotation.xml,导入context命名空间。

<!--指定spring ioc容器扫描的包-->
<context:component-san base-package="anotation">
<bean></bean>

9.2 过滤表达式

<context:include-filter><context:exclude-filter>支持多种类型的过滤表达式

annotation: 所有标注了xxxAnnotation的类

assinable: 所有继承或扩展xxxService的类

aspectj: 所有类名以Service结束的类以及继承或扩展它们的类。
该类型采用AspejctJ进行过滤。

regex:
所有com.atguigu.anno包下的类。该类型采用正则表达式根据类的类名进行过滤。

custom:
采用xxxTypeFilter通过代码的方式定义过滤规则。该类必须实现
org.springframework.core.type.TypeFilter接口

component–controller-repository-service

<!--指定spring ioc容器扫描的包-->
<bean>
    <context:component-san base-package="com.atguigu.spring.beans.anotation">
<context:execlude-filter type="annotation" use-default-filter="true" expression="org.springframework.stereotype.Repository" />

</bean>

9.3 泛型依赖注入

BaseService —-> @Autowired BaseRepository
BaseRepository
User
UserService extends BaseService —-> @Service
UserRepository extends BaseRepository —-> @Repository

父类泛型之间建立引用的。
BaseService当中有个成员变量,或者方法是关于BaseRepository的。
这个变量或方法用@Autowired来自动装配。
这样,父类泛型之间就建立起了引用了。

子类指定user泛型的Service和UserRepository之间也就自动地建立了引用了。

然后在测试的时候,从IOC容器中拿到userService这个bean。调用其中的方法,就会自动装配对应的Repository子类了。

总结一下:
父类之间的引用关系,对应子类之间自动引用。
子类都用注解交给IOC管理之后,很容易调用对用子类泛型。

猜你喜欢

转载自blog.csdn.net/oneqinglong/article/details/72972276