目录

1.Spring配置/管理bean介绍

2.基于XML配置bean

2.1基于id来获取bean对象

2.2基于类型获取bean对象

2.3通过指定构造器配置bean对象

2.4通过p名称空间配置bean 

2.5通过ref配置bean(实现依赖注入)

2.6注入内部Bean对象,依赖注入另一种方式

2.7 注入集合/数组类型

使用util名称空间创建list

级联属性赋值配置

2.8 通过静态工厂获取对象

2.9通过实例工厂配置bean 

2.10 通过FactoryBean获取bean对象(重点) 

2.11 bean配置信息重用(继承)

 2.12 Bean创建的顺序

2.13 Bean对象的单例和多例 

2.14Bean的生命周期 

 2.15 配置Bean的后置处理器[重点!难点!]

2.16 通过属性文件给Bean注入值 

 2.17 基于XML的Bean的自动装配

 2.18 Spring的EL表达式配置Bean[基础演示]

 2.19 基于注解配置Bean【重点】

2.19.1快速入门案例 

2.19.2 细节分析 


1.Spring配置/管理bean介绍

Spring-IOC的配置所需要的jar包有四个。

如果你用maven配置则需要导入以下代码在pom.xml文件中

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>spring01</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
<!-- 引入ioc的beans基本包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.2.9.RELEASE</version>
        </dependency>
<!--引入ioc的core基本包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.2.9.RELEASE</version>
        </dependency>
<!--引入ioc的context基本包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.9.RELEASE</version>
        </dependency>
<!--引入ioc的expression的基本包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>5.2.9.RELEASE</version>
        </dependency>
<!--引入一些日志文件-->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
<!--加入单元测试的类-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>
<!--加入简化开发pojo的jar包-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.4</version>
        </dependency>
    </dependencies>
</project>

2.基于XML配置bean

注意: xml文件中property属性的配置name的名字必须和你的类的属性名一样,底层是通过类的setter方法进行创建的。

首先会创建一个Monster类

package spring.bean;
/**
 * @author sn
 */
public class Monster {
    private Integer id;
    private String name;
    private String skill;

    //写一个无参构造函数,spring是用反射来创建对象的

    public Monster() {
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getSkill() {
        return skill;
    }

    public void setSkill(String skill) {
        this.skill = skill;
    }

    @Override
    public String toString() {
        return "Monster{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", skill='" + skill + '\'' +
                '}';
    }
}

2.1基于id来获取bean对象

基于id获取bean的案例,在我的另外一个文章中

2.2基于类型获取bean对象

1. 按类型来获取 bean, 要求 Spring容器中的同一个类的 bean 只能有一个 , 否则会抛出异常
NoUniqueBeanDefinitionException
2.  应用场景:比如 Controller控制器, XxxService 在一个线程 中只需要一个对象实例 ( 单例 ) 的情况
3. 注意 : 在容器配置文件 ( 比如 beans.xml) 中给属性赋值 , 底层是通过 setter 方法完成的 , 这也是为什么我们需要提供 setter 方法的原因
这里可以看看我手写底层Spring如何通姑XML创建对象的   链接,去看看

 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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--通过类型来配置bean-->
  <bean class="spring.bean.Monster">
    <property name="id" value="1"/>
    <property name="name" value="小红花"/>
    <property name="skill" value="向阳而生"/>
  </bean>
</beans>
    @Test
    public void getTypeBean()
    {
        //先获取容器
        ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        Monster bean = ioc.getBean(Monster.class);
        System.out.println(bean);
    }

 结果

 如果配置了两个bean对象,且用类型来获取该对象(这里bean在xml在配置一个)(X)

如果在Monster中没有setId方法(setter)(X)

我们知道对象在Spring容器的创建是通过反射创建的,属性是通过类对应的setter方法构建的

如果没有setter方法,那么对象在Spring容器中构建不出,就会报错! 

2.3通过指定构造器配置bean对象

提示:反射机制创建对象有两种:

1:通过指定的构造器创建对象。

2:   通过对象中的setter和getter方法创建

1:当你用指定构造器创建对象是,就是用这个类中的有参构造创建

2:当你使用id/类型/p命名空间等这些都是用其中的getter和setter方法去创建的对象。(前提是你必须拥有它的无参构造函数!!)

首先要在Monster中写一个全参的构造函数

  public Monster(Integer id, String name, String skill) {
        this.id = id;
        this.name = name;
        this.skill = skill;
    }

XML文件中通过构造器配置bean对象 (构造器参数的设计三种方式)

1.constructor-arg标签用来指定构造器的参数

2.用index索引表示构造器的第几个参数

<?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  -->
  <bean class="spring.bean.Monster" id="monster02">
   <constructor-arg value="13" index="0"/>
   <constructor-arg value="花小龙" index="1"/>
   <constructor-arg value="自律遇见更好地自己!" index="2"/>
  </bean>
</beans>

1.constructor-arg标签用来指定构造器的参数

2.用name表示构造器的第几个参数

<?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  -->
    <bean class="spring.bean.Monster" id="monster03">
        <constructor-arg value="14" name="id"/>
        <constructor-arg value="王老师" name="name"/>
        <constructor-arg value="从那天起我再也没羡慕过谁!" name="skill"/>
    </bean>
</beans>

1.constructor-arg标签用来指定构造器的参数

2.用type表示构造器的参数(按顺序来)

<?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  -->
   <bean class="spring.bean.Monster" id="monster04">
        <constructor-arg value="520" type="java.lang.Integer"/>
        <constructor-arg value="陈泽" type="java.lang.String"/>
        <constructor-arg value="在一起!" type="java.lang.String"/>
    </bean>
</beans>

测试代码

   @Test
    public void getConstructorBean()
    {
        //先获取容器
        ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        Monster bean1 = ioc.getBean("monster02", Monster.class);
        Monster bean2 = ioc.getBean("monster03", Monster.class);
        Monster bean3 = ioc.getBean("monster04", Monster.class);
        System.out.println(bean1);
        System.out.println(bean2);
        System.out.println(bean3);
    }

结果: 

2.4通过p名称空间配置bean 

 p命名空间绑定,直接alt+enter绑定命名空间 (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.xsd">
<!--通过p命名空间来获取-->
    <bean class="spring.bean.Monster" id="monster05"
        p:id = "1"
        p:name="小哥"
        p:skill="冒昧呀!"
    />
</beans>

测试代码 

    @Test
    public void getPNameBean()
    {
        //先获取容器
        ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        Monster bean = ioc.getBean("monster05", Monster.class);
        System.out.println(bean);
    }

2.5通过ref配置bean(实现依赖注入)

spring ioc 容器 , 可以通过 ref 来实现 bean 对象的 相互引用
因为在spring容器中,是通过反射创建对象的,其中的属性方法,都需要xml文件/或者注解的形式进行配置完整的对象。(这是反射的基础),那如果一个对象的属性要依赖另外一个对象,如何去实现,这就是依赖注入,通过ref去实现!
需求分析:MemberService-->依赖与-->MemberDao。调用add方法时,同时也调用Dao的add
配置MemberDao类
package spring.dao;

/**
 * @author sn
 */
public class MemberDao {
    public MemberDao() {
        System.out.println("MemberDao构造函数被执行");
    }

    public void add()
    {
        System.out.println("MemberDao成功添加了一个人");
    }

}

配置MemberService类 

package spring.service;

import spring.dao.MemberDao;

/**
 * @author sn
 */
public class MemberService {
    private MemberDao memberDao;

    public MemberDao getMemberDao() {
        return memberDao;
    }

    public void setMemberDao(MemberDao memberDao) {
        this.memberDao = memberDao;
    }

    public void add()
    {
        System.out.println("MemberService里面的add方法被调用");
        memberDao.add();
    }

}

配置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">
<!--通过ref实现依赖注入-->
<!--首先配置两个独立的对象,要实现对象之间的组装,依赖注入,用到ref
指向id为dao的对象(某个对象的属性是要依赖另外一个对象的)    -->
    <bean class="spring.dao.MemberDao" id="dao"/>
    <bean class="spring.service.MemberService" id="memberService">
        <property name="memberDao" ref="dao"/>
    </bean>
</beans>

测试类 

@Test
    public void setBeanByref()
    {
        //先获取容器
        ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        MemberService bean = ioc.getBean("memberService", MemberService.class);
        bean.add();
    }

结果 

具体说明解释 

@1 xml文件的扫描是通过全局扫描的,所以在ref配置对象的id的时候,如另外一个对象在后面,也不会报错,比如在beandefinitonMap里面就有所有的对象的id。

@2 依赖注入,就是一个对象要用到另外一个对象时,spring容器可以去实现。

@3 底层剖析,ref是如何依赖注入对象,或者说是如何精确找到要用的对象的

在spring容器创建过后,可以看到在singletonObject(单例数组对象中) MemberDao是3344,你可以把它理解成hash值。 

在这里我们看到了MemberService他的哈希值是3346,他引用的对象MemberDao的值是3343。底层就是通过这种编号来找的。 

2.6注入内部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实现依赖注入-->
    <bean class="spring.dao.MemberDao" id="dao"/>
    <bean class="spring.service.MemberService" id="memberService">
        <property name="memberDao">
            <bean class="spring.service.MemberService" />
        </property>
    </bean>
</beans>

结果也是一样的

2.7 注入集合/数组类型

案例:通过xml中的配置,实现spring容器对集合map list set array properties的注入

2. Properties 集合的特点
1) 这个 Properties Hashtable 的子类 , key-value 的形式
2) key string value 也是 string

定义一个Master类

package spring.bean;

import java.util.*;

/**
 * @author sn
 */
public class Master {
    private String name;
    private List<Monster> monsterList;
    private Map<String, Monster> monsterMap;
    private Set<Monster> monsterSet;
    private String[] monsterName;
    //这个 Properties 是 Hashtable 的子类 , 是 key-value 的形式
//这里 Properties key 和 value 都是 String
    private Properties pros;

    public Master() {
    }

    public Master(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    public List<Monster> getMonsterList() {
        return monsterList;
    }

    public void setMonsterList(List<Monster> monsterList) {
        this.monsterList = monsterList;
    }

    public Map<String, Monster> getMonsterMap() {
        return monsterMap;
    }

    public void setMonsterMap(Map<String, Monster> monsterMap) {
        this.monsterMap = monsterMap;
    }

    public Set<Monster> getMonsterSet() {
        return monsterSet;
    }

    public void setMonsterSet(Set<Monster> monsterSet) {
        this.monsterSet = monsterSet;
    }

    public String[] getMonsterName() {
        return monsterName;
    }

    public void setMonsterName(String[] monsterName) {
        this.monsterName = monsterName;
    }

    public Properties getPros() {
        return pros;
    }

    public void setPros(Properties pros) {
        this.pros = pros;
    }

    @Override
    public String toString() {
        return "Master{" +
                "name='" + name + '\'' +
                ", monsterList=" + monsterList +
                ", monsterMap=" + monsterMap +
                ", monsterSet=" + monsterSet +
                ", monsterName=" + Arrays.toString(monsterName) +
                ", pros=" + pros +
                '}';
    }
}

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.xsd">

<!--配置Master对象-->
    <bean class="spring.bean.Master" id="master">
        <property name="name" value="主人1"/>
        <property name="monsterList">
            <list>
                <!--通过引入的方式-->
                <ref bean="monster01"/>
                <ref bean="monster02"/>
                <bean class="spring.bean.Monster">
                    <property name="name" value="小老鼠"/>
                    <property name="id" value="2"/>
                    <property name="skill" value="会钻洞"/>
                </bean>
            </list>
        </property>
    </bean>
<!--对map属性进行一个赋值-->
    <bean class="spring.bean.Master" id="master2">
        <property name="name" value="主人2"/>
        <property name="monsterMap">
            <map>
                <entry>
                    <key>
                        <value>monster01</value>
                    </key>
                    <ref bean="monster01"/>
                </entry>
                <entry key="monster002">
                    <bean class="spring.bean.Monster">
                        <property name="name" value="小红"/>
                        <property name="id" value="1"/>
                        <property name="skill" value="摘樱桃"/>
                    </bean>
                </entry>
            </map>
        </property>
    </bean>

<!--对set属性进行一个赋值-->
    <bean class="spring.bean.Master" id="master3">
        <property name="name" value="主人三"/>
        <property name="monsterSet">
            <set>
                <ref bean="monster02"/>
                <ref bean="monster03"/>
                <bean class="spring.bean.Monster">
                    <property name="id" value="15"/>
                    <property name="name" value="金角大王"/>
                    <property name="skill" value="会洗澡"/>
                </bean>
            </set>
        </property>
    </bean>

<!--对数组进行赋值-->
    <bean class="spring.bean.Master" id="master4">
        <property name="name" value="主人4"/>
        <property name="monsterName">
            <array>
                <value>小球1</value>
                <value>小球2</value>
                <value>小球3</value>
            </array>
        </property>
    </bean>
<!--对properties进行赋值-->
    <bean class="spring.bean.Master" id="master5">
        <property name="pros">
            <props>
                <prop key="username">张三</prop>
                <prop key="password">12354</prop>
            </props>
        </property>
    </bean>
<!--通过指定构造器配置bean  -->
  <bean class="spring.bean.Monster" id="monster02">
   <constructor-arg value="13" index="0"/>
   <constructor-arg value="花小龙" index="1"/>
   <constructor-arg value="自律遇见更好地自己!" index="2"/>
  </bean>

    <bean class="spring.bean.Monster" id="monster03">
        <constructor-arg value="14" name="id"/>
        <constructor-arg value="王老师" name="name"/>
        <constructor-arg value="从那天起我再也没羡慕过谁!" name="skill"/>
    </bean>

    <bean class="spring.bean.Monster" id="monster04">
        <constructor-arg value="520" type="java.lang.Integer"/>
        <constructor-arg value="陈泽" type="java.lang.String"/>
        <constructor-arg value="在一起!" type="java.lang.String"/>
    </bean>
<!--通过p命名空间来获取-->
    <bean class="spring.bean.Monster" id="monster05"
        p:id = "1"
        p:name="小哥"
        p:skill="冒昧呀!"
    />

<!--通过ref实现依赖注入-->
<!--首先配置两个独立的对象,要实现对象之间的组装,依赖注入,用到ref
指向id为dao的对象(某个对象的属性是要依赖另外一个对象的)    -->
    <bean class="spring.dao.MemberDao" id="dao"/>
    <bean class="spring.service.MemberService" id="memberService">
        <property name="memberDao" ref="dao"/>
    </bean>

  <!--通过类型来配置bean
  <bean class="spring.bean.Monster">
    <property name="id" value="1"/>
    <property name="name" value="小红花"/>
    <property name="skill" value="向阳而生"/>
  </bean>-->

    <!--
    1.配置Monster对象/javabean
    2.在beans中可以配置多个bean
    3.class属性指定的是类的全路径
    4.id属性表示java对象在spring容器中的id,通过id可以获取对象
    5.<property name="skill" value="向阳而生"/>是用来给该对象赋值
-->
<bean class="spring.bean.Monster" id="monster01">
    <property name="id" value="1"/>
    <property name="name" value="小红花"/>
    <property name="skill" value="向阳而生"/>
</bean>
</beans>

测试文件 

 @Test
    public void setBeanByList()
    {
        //先获取容器
        ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        Master bean = ioc.getBean("master", Master.class);
        System.out.println("master=>"+bean);
    }

    @Test
    public void setBeanByMap()
    {
        //先获取容器
        ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        Master bean = ioc.getBean("master2", Master.class);
        System.out.println("master=>"+bean);
    }

    @Test
    public void setBeanBySet()
    {
        //先获取容器
        ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        Master bean = ioc.getBean("master3", Master.class);
        System.out.println("master=>"+bean);
    }

    @Test
    public void setBeanByArray()
    {
        //先获取容器
        ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        Master bean = ioc.getBean("master4", Master.class);
        System.out.println("master=>"+bean);
    }

    @Test
    public void setBeanByProperties()
    {
        //先获取容器
        ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        Master bean = ioc.getBean("master5", Master.class);
        System.out.println("master=>"+bean);
    }

使用util名称空间创建list

通过 util 名称空间来创建 list 集合,可以当做创建 bean 对象的工具来使用

他的作用:就是当多个对象进行复用该list集合的时候,就可以直接引用,看代码。

<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"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<!--定义一个util:list命名空间 -->
    <util:list id="books">
        <value>三国演义</value>
        <value>西游记</value>
        <value>红楼梦</value>
        <value>水浒传</value>
    </util:list>

    <!--配置BookStore对象-->
    <bean class="spring.bean.BookStore" id="bookStore">
        <property name="bookList" ref="books"/>
    </bean>
</beans>

不需要和之前List的注入时,要将所有List写出来,当如果多个对象都有这个List,就可以进行一个代码的复用 。

级联属性赋值配置

spring ioc 容器 , 可以直接给对象属性的属性赋值, 即级联属性赋值

需求是:员工类有名字和部门类,创建对象的时候给他的名字,以及属性的属性部门的名字赋值 

 Dept部门类

package spring.bean;

/**
 * @author sn
 */
public class Dept {
    private String name;

    public Dept() {
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Dept{" +
                "name='" + name + '\'' +
                '}';
    }
}

Emp员工类

package spring.bean;

/**
 * @author sn
 */
public class Emp {
    private String name;
    public Emp() {}
    private Dept dept;

    public String getName() {
        return name;
    }

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

    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "name='" + name + '\'' +
                ", dept=" + dept +
                '}';
    }
}

测试类

  @Test
    public void setBeanByJILian()
    {
        //先获取容器
        ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        Emp emp = ioc.getBean("emp", Emp.class);
        System.out.println("emp=>"+emp);
    }

beans.xml

<!--级联属性赋值-->
    <bean class="spring.bean.Dept" id="dept"/>
    <bean class="spring.bean.Emp" id="emp">
        <property name="name" value="张三"/>
        <property name="dept" ref="dept"/>
        <property name="dept.name" value="语言开发部门"/>
    </bean>

结果 

2.8 通过静态工厂获取对象

spring ioc 容器 , 可以通过静态工厂获取 bean 对象

 具体解释:

 使用静态工厂,就算创建了两个静态工厂,但是他们仍然是同一个工厂。就相当于静态类,有且只有一个

 静态工厂类

package spring.bean;

import java.util.HashMap;
import java.util.Map;

/**
 * @author sn
 */
public class MyStaticFactory {
    private static Map<String, Monster> monsterMap;
    static {
        monsterMap = new HashMap<String, Monster>();
        monsterMap.put("monster_01", new Monster(100, "黄袍怪", "一阳指"));
        monsterMap.put("monster_02", new Monster(200, "九头金雕", "如来神掌"));
    }
    public static Monster getMonster(String key) {
        return monsterMap.get(key);
    }
}

 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"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<!--通过静态工厂获取bean对象
    factory-method:是从静态工厂中要使用的方法
    constructor-arg:你要从工厂里面取出对象的id
    -->
    <bean id="my_monster" class="spring.bean.MyStaticFactory"
          factory-method="getMonster">
        <!-- constructor-arg 标签提供 key -->
        <constructor-arg value="monster_01"/>
    </bean>
</beans>

2.9通过实例工厂配置bean 

 spring ioc 容器, 可以通过实例工厂获取 bean 对象

实例工厂和静态工厂的异同

相同:他们都是从自创的工厂中直接获取对象,不需要在xml中对对象重新进行信息的配置

不同:

类比于Java的静态类和普通类

1. 在写法上,静态工厂,不需要一个真正的工厂对象,就可以调用里面的方法。而实例工厂,必须要用一个实例工厂对象才行。

2. 静态工厂有且只有一个,每个从静态工厂中拿出id一样的对象都是相同的。

    实例工厂可以有多个,当你创建多个实例工厂对象,从不同工厂拿出id一样的对象是不同的。

 假如你配置了两个实例工厂对象,那么这两个工厂就是不同的工厂,里面的对象也只是属性值都相同的不同的对象。

实例工厂

package spring.bean;

import java.util.HashMap;
import java.util.Map;

/**
 * @author sn
 */
public class MyInstanceFactory {
    private Map<String, Monster> monster_map;

    //通过普通代码块进行初始化
    {
        monster_map = new HashMap<>();
        monster_map.put("monster03", new Monster(300, "牛魔王~", "芭蕉扇~"));
        monster_map.put("monster04", new Monster(400, "狐狸精~", "美人计~"));
    }

    //写一个方法返回Monster对象
    public Monster getMonster(String key) {
        return monster_map.get(key);
    }
}

 XML文件

<!--通过实例工厂配置bean对象-->
    <!--配置monster对象, 通过实例工厂
     1. factory-bean 指定使用哪个实例工厂对象返回bean
     2. factory-method 指定使用实例工厂对象的哪个方法返回bean
     3. constructor-arg value="monster03" 指定获取到实例工厂中的哪个monster -->
    <bean class="spring.bean.MyInstanceFactory" id="myInstanceFactory"/>
    <bean factory-bean="myInstanceFactory" factory-method="getMonster" id="monster">
        <constructor-arg value="monster03"/>
    </bean>

2.10 通过FactoryBean获取bean对象(重点) 

spring ioc 容器 , 通过 FactoryBean 获取 bean 对象 ( 重点 )

FactoryBean实现这个接口 

MyFactoryBean

package spring.bean;

import org.springframework.beans.factory.FactoryBean;

import java.util.HashMap;
import java.util.Map;

/**
 * @author sn
 */
public class MyFactoryBean implements FactoryBean<Monster> {
    //key就是要获取的对像的key
    private String key;
    private Map<String,Monster> monster_map;
    //用普通代码块,完成初始化
    {
        monster_map = new HashMap<>();
        monster_map.put("monster_01", new Monster(100, "黄袍怪", "一阳指"));
        monster_map.put("monster_02", new Monster(200, "九头金雕", "如来神掌"));
    }

    public void setKey(String key) {
        this.key = key;
    }

    @Override
    public Monster getObject() throws Exception {
        return monster_map.get(key);
    }

    @Override
    public Class<?> getObjectType() {
        return Monster.class;
    }

    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }
}

 XML

1. 通过 FactoryBean 来获取 bean 对象
2. name="keyVal" 就是 MyFactoryBean 定义的 setKeyVal 方法
3. value="monster_01" ,就是给 keyVal 的值
    <!--配置monster对象通过FactorBean获取-->
<bean class="spring.bean.MyFactoryBean" id="myFactoryBean">
    <property name="key" value="monster_01"/>
</bean>

2.11 bean配置信息重用(继承)

 spring ioc 容器, 提供了一种继承的方式来实现 bean 配置信息的重用

  1. 如果bean指定了 abstract="true", 表示该bean对象, 是专门用于被继承 。
  2. 本身这个bean就不能被获取/实例化,也就是说你在Spring容器中获取不了该对象。

  3. parent="monster10" 指定当前这个配置的对象的属性值从 id=monster10的对象来。

<!--配置Monster对象-->
<bean class="spring.bean.Monster" id="monster10">
    <property name="name" value="陆雪琪"/>
    <property name="id" value="1"/>
    <property name="skill" value="爱上张小凡"/>
</bean>
    <!--
    1. 配置Monster对象
    2.但是这个对象的属性值和 id="monster10"对象属性一样
    3.parent="monster10" 指定当前这个配置的对象的属性值从 id=monster10的对象来 -->
    <bean id="monster11" class="spring.bean.Monster" parent="monster10"/>
    <!--配置Monster对象 
    1. 如果bean指定了 abstract="true", 表示该bean对象, 是用于被继承 
    2. 本身这个bean就不能被获取/实例化 -->
    <bean class="spring.bean.Monster" id="monster13" abstract="true">
        <property name="name" value="陆雪琪"/>
        <property name="id" value="1"/>
        <property name="skill" value="爱上张小凡"/>
    </bean>

 2.12 Bean创建的顺序

1. 在 spring 的 ioc 容器, 默认是按照配置的顺序创建 bean 对象
<bean id="student01" class="com.bean.Student" />
<bean id="department01" class="com.bean.Department" />
会先创建 student01 这个 bean 对象,然后创建 department01 这个 bean 对象
2. 如果这样配置
<bean id="student01" class="com.bean.Student" depends-on ="department01"/>
<bean id="department01" class="com.bean.Department" />
会先创建 department01 对象,再创建 student01 对象

3.注意重点

Bean对象的创建一直都是按顺序进行创建。 Spring容器创建是对整个XML文件进行扫描,以一个整体进行创建的

1. 先看下面的配置 , 请问两个 bean 创建的顺序是什么 ? 并分析执行流程
1) 先创建 id=dao
2) 再创建 id = memberService
3) 调用 memberService.setMemberDao() 完成引用

2. 先看下面的配置 , 请问两个 bean 创建的顺序是什么 , 并分析执行流程
1) 先创建 id = memberService
2) 再创建 id=dao
3) memberService.setMemberDao() 完成引用

2.13 Bean对象的单例和多例 

1. 在 spring ioc 容器 , 默认是按照单例创建的 ,即配置一个 bean 对象后, ioc 容器只会 创建一个 bean 实例。
2. 如果 , 我们希望 ioc 容器配置的某个 bean 对象, 是以多个实例形式创建的则可以通过配置
scope="prototype" 来指定
3. 如果bean的配置是 scope="singleton" lazy-init="true" 这时,ioc容器就不会提前创建该对象 , 而是当执行getBean方法的时候,才会创建对象

 xml

    <!--配置对象
     1. 在默认情况下 scope属性是 singleton
     2. 在ioc容器中, 只要有一个这个bean对象
     3. 当程序员执行getBean时, 返回的的是同一个对象
     4. 如果我们希望每次getBean返回一个新的Bean对象,则可以scope="prototype"
     5. 如果bean的配置是 scope="singleton" lazy-init="true" 这时,
     ioc容器就不会提前创建该对象 , 而是当执行getBean方法的时候,才会创建对象 -->
    <bean class="spring.bean.Monster" id="monster2" scope="prototype"
        p:id="3"
        p:name="小王"
        p:skill="会生孩"
    />

测试代码

    @Test
    public void testBeanByScope()
    {
        //先获取容器
        ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        Monster bean = ioc.getBean("monster2", Monster.class);
        Monster bean2 = ioc.getBean("monster2", Monster.class);
        System.out.println("bean = bean2:"+ (bean == bean2));
    }

最后的结果是false,因为指定了scope=prototype 

使用细节

1. 默认是单例 singleton, 在启动容器时 , 默认会创建 , 并放入到 singletonObjects 集合
2. <bean scope="prototype" > 设置为多实例机制后 , bean 是在 getBean() 时才创
3. 如 果 是 单 例 singleton, 同 时 希 望 在 getBean 时 才 创 建 , 可 以 指 定 懒 加 载
lazy-init ="true" ( 注意默认是 false)

4. 通常情况下 , lazy-init 就使用默认值 false , 在开发看来 , 用空间换时间是值得的 , 除非
有特殊的要求 .
5. 如果 scope="prototype" 这时你的 lazy-init 属性的值不管是 ture, 还是 false 都是在
getBean 时候,才创建对象 .

2.14Bean的生命周期 

Bean对象是由JVM虚拟机创建的,他具体创建bean对象的执行流程如下:

1. 执行构造器
2. 执行 set 相关方法
3. 调用 bean 的初始化的方法(需要配置)
4. 使用 bean
5. 当容器关闭时候,调用 bean 的销毁方法(需要配置)

1. init-method="init" 指定bean的初始化方法 , 在setter方法后执行
2. init方法执行的时机,有spring容器来控制
3. destroy-method="destroy" 指定bean的销毁方法, 在容器关闭的时候执行
4. destroy方法执行的时机,有spring容器来控制

创建一个House类 

package spring.bean;

/**
 * @author sn
 */
public class House {
    private String name;

    public House() {
        System.out.println("House()构造函数被调用");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("House setName()="+name);
        this.name = name;
    }

    public void init()
    {
        System.out.println("House init()..");
    }

    public void destroy() {
        System.out.println("House destory()..");
    }

}

<!--   配置House对象,演示Bean的生命周期
        1. init-method="init" 指定bean的初始化方法 , 在setter方法后执行
        2. init方法执行的时机,有spring容器来控制
        3. destroy-method="destroy" 指定bean的销毁方法, 在容器关闭的时候执行
        4. destroy方法执行的时机,有spring容器来控制
        -->
   <bean class="spring.bean.House" id="house"
    init-method="init" destroy-method="destroy">
    <property name="name" value="小马"/>
   </bean>
    @Test
    public void testBeanByLive()
    {
        //先获取容器
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
        House house = ioc.getBean("house", House.class);
        System.out.println("使用"+house);

        //关闭spring容器
        ((ConfigurableApplicationContext) ioc).close();
    }

注意这里为什么要转换类型,再调用其close方法呢:因为ApplicatonContext没有这个方法,那么他的字接口有。 

 2.15 配置Bean的后置处理器[重点!难点!]

1. spring ioc 容器 , 可以配置 bean 的后置处理器
2. 该处理器 / 对象会在 bean 初始化方法 调用前和初始化方法调用后被调用
3. 程序员可以在后置处理器中编写自己的代码
4. 可以将该处理器可以看做一个对象
5. 只要在xml文件中创建了该后置处理器对象,他会作用于所有的xml中配置的对象
6. 怎么执行到这个方法?=> 使用 AOP(反射+动态代理+IO+容器+注解)
7. 有什么用? => 可以 对 IOC 容器中所有的对象进行统一处理 , 比如 日志处理 / 权限的校
/ 安全的验证 / 事务管理
8. 创建后置处理器对象,要实现BeanPostProcesser接口

后置处理器对象创建 

package spring.bean;

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

/**
 * @author sn
 * * 这是一个后置处理器, 需要实现 BeanPostProcessor接口
 */
public class MyBeanPostProcessor implements BeanPostProcessor {

    /**
     * 什么时候被调用: 在Bean的init方法前被调用
     * @param bean 传入的在IOC容器中创建/配置Bean
     * @param beanName 传入的在IOC容器中创建/配置Bean的id
     * @return Object 程序员对传入的bean 进行修改/处理【如果有需要的话】 ,返回
     * @throws BeansException
     */

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization().. bean="
                + bean + " beanName=" + beanName);

        //初步体验案例: 如果类型是House的统一改成 上海豪宅
        //对多个对象进行处理/编程==>切面编程
       /* if(bean instanceof House) {
            ((House)bean).setName("上海豪宅~");
        }*/
        return null;
    }

    /**
     * 什么时候被调用: 在Bean的init方法后被调用
     * @param bean  传入的在IOC容器中创建/配置Bean
     * @param beanName 传入的在IOC容器中创建/配置Bean的id
     * @return 程序员对传入的bean 进行修改/处理【如果有需要的话】 ,返回
     * @throws BeansException
     */

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

beans02.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">
    <!--配置House对象-->
    <bean destroy-method="destroy" init-method="init" id="house" class="spring.bean.House">
    <property value="住宅" name="name"/>
    </bean>

    <bean destroy-method="destroy" init-method="init" id="house02" class="spring.bean.House">
    <property value="豪宅" name="name"/>
    </bean>

    <!--配置了一个Monster对象-->
    <!--配置后置处理器对象
    1. 当我们在beans02.xml 容器配置文件 配置了 MyBeanPostProcessor
    2. 这时后置处理器对象,就会作用在该容器创建的Bean对象
    3. 已经是针对所有对象编程->切面编程AOP -->
    <bean id="myBeanPostProcessor" class="spring.bean.MyBeanPostProcessor"/>

</beans>

测试类 

    @Test
    public void testBeanByPostProcesser()
    {
        //先获取容器
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans02.xml");
        House house = ioc.getBean("house", House.class);
        House house2 = ioc.getBean("house02", House.class);
        System.out.println("使用"+house);
        System.out.println("使用"+house2);
        //关闭spring容器
        ((ConfigurableApplicationContext) ioc).close();
    }

 结果分析

 

2.16 通过属性文件给Bean注入值 

 一切都在代码中的注释中进行解释,请耐心看完。

如何处理配置文件中中文的问题:

在配置文件中通过工具,将中文转换为Unicode编码就可以了

Unicode编码转换 | Unicode在线转换 —在线工具

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

    <!--指定属性文件
     1. 先把这个文件修改成提示All Problem
     2. 提示错误,将光标放在context 输入alt+enter 就会自动引入namespace
     3. location="classpath:my.properties" 表示指定属性文件的位置
     4. 提示,需要带上 classpath
     5. 属性文件有中文,需要将其转为unicode编码-> 使用工具 -->
    <context:property-placeholder location="classpath:my.properties"/>
    <!--配置Monster对象
    1.通过属性文件给monster对象的属性赋值
    2. 这时我们的属性值通过${属性名}
    3. 这里说的 属性名 就是 my.properties文件中的 k=v 的k -->
    <bean id="monster100" class="spring.bean.Monster">
    <property value="${id}" name="id"/>
    <property value="${skill}" name="skill"/>
    <property value="${name}" name="name"/>

</bean>
</beans>

配置文件 

id=100
name=jd
skill=hello,boy

 2.17 基于XML的Bean的自动装配

spring ioc 容器,可以实现自动装配 bean

首先配置三个类OrderAvtion-->OrderService-->OrderDao

OrderAction 

package spring.controller;


import spring.service.OrderService;

/**
 * @author sn
 * Servlet就是Controller
 */
public class OrderAction {
    //属性OrderService
    private OrderService orderService;

    //getter
    public OrderService getOrderService() {
        return orderService;
    }

    //setter
    public void setOrderService(OrderService orderService) {
        this.orderService = orderService;
    }
}

 OrderService

package spring.service;

import spring.dao.OrderDao;

/**
 * @author sn
 * Service类
 */
public class OrderService {
    //OrderDao属性
    private OrderDao orderDao;

    //getter
    public OrderDao getOrderDao() {
        return orderDao;
    }
    //setter
    public void setOrderDao(OrderDao orderDao) {
        this.orderDao = orderDao;
    }
}

 OrderDao

package spring.dao;

/**
 * @author sn
 * DAO类 只有一个saveOrder()方法
 */
public class OrderDao {
    //方法。。。
    public void saveOrder() {
        System.out.println("订单...");
    }
}
    <!--配置OrderService
    1. autowire="byType" 表示 在创建 orderService时通过类型的方式 给对象属性 自动完成赋值/引用
    2. 比如OrderService 对象有 private OrderDao orderDao
    3. 就会在容器中去找有没有 OrderDao类型对象
    4. 如果有,就会自动的装配, 如果是按照 byType 方式来装配, 这个容器中,不能有两个的OrderDao类型对象
    5. 如果你的对象没有属性, autowire就没有必要写
    6. 其它类推..
    7. 如果我们设置的是 autowire="byName" 表示通过名字完成自动装配
    8. 比如下面的 autowire="byName" class="spring.service.OrderService"
        1) 先看 OrderService 属性 private OrderDao orderDao
        2) 再根据这个属性的setXxx()方法的 xxx 来找对象id
        3) public void setOrderDao() 就会找id=orderDao对象来进行自动装配
        4) 如果没有就装配失败 -->
    <!--配置orderDao对象-->
    <bean class="spring.dao.OrderDao" id="orderDao"/>
<!--配置orderService对象-->
    <bean autowire="byType" class="spring.service.OrderService" id="orderService"/>
<!--配置orderAction-->
    <bean autowire="byName" class="spring.controller.OrderAction" id="orderAction"/>

具体解释 

@1 在对象中有一个属性为autowire,里面几种自动装配的方法,这里具体介绍了byName和byType
@2 如果使用byType,对于OrderAction中有一个对象属性为orderService的对象,他会去扫描整个Spring容器,找到一个类型是OrderService的对象进行一个自动的装配,没有找到责装配失败。
@3 注意的是如果通过byType的形式,在Spring容器中只能有一种这种类型的对象
@4 如果采用byName的形式,他会去寻找OrderAction中的对于对象属性的Setter方法所对应的id,而不是去找对象属性的变量名的id比如,在上诉代码中寻找setOrderService()方法中的,id为orderService的对象进行装配

 2.18 Spring的EL表达式配置Bean[基础演示]

1. Spring Expression Language Spring 表达式语言,简称 SpEL 。支持运行时查询并可以操 作对象。
2. EL 表达式一样, SpEL 根据 JavaBean 风格的 getXxx() setXxx() 方法定义的属性访问 对象
3. SpEL 使用 #{…} 作为定界符,所有在大框号中的字符都将被认为是 SpEL 表达式。

 配置SpELBean类

package spring.bean;

/**
 * @author sn
 */
public class SpELBean {
    private String name;
    private Monster monster;
    private String monsterName;
    private String crySound;
    private String bookName;
    private Double result;

    public SpELBean() {
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Monster getMonster() {
        return monster;
    }
    public void setMonster(Monster monster) {
        this.monster = monster;
    }
    public String getMonsterName() {
        return monsterName;

    }
    public void setMonsterName(String monsterName) {
        this.monsterName = monsterName;
    }
    public String getCrySound() {
        return crySound;
    }
    public void setCrySound(String crySound) {
        this.crySound = crySound;
    }
    public String getBookName() {
        return bookName;
    }
    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public Double getResult() {
        return result;
    }
    public void setResult(Double result) {
        this.result = result;
    }
    public String cry(String sound) {
        return "发出 " + sound + "叫声...";
    }
    public static String read(String bookName) {
        return "正在看 " + bookName;
    }
}

我觉得这个EL表达式挺方便的

<?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">

    <!-- spring el 表达式使用
    1. 通过spel给bean的属性赋值 -->
<bean class="spring.bean.SpELBean" id="spELBean">
    <!-- sp el 给字面量 -->
    <property value="#{'效率'}" name="name"/>
    <!-- sp el 引用其它bean -->
    <property value="#{monster01}" name="monster"/>
    <!-- sp el 引用其它bean的属性值 -->
    <property value="#{monster01.name}" name="monsterName"/>
    <!-- sp el 调用普通方法(返回值) 赋值 -->
    <property value="#{spELBean.cry('嘟嘟的..')}" name="crySound"/>
    <!-- sp el 调用静态方法(返回值) 赋值 -->
    <property value="#{T(spring.bean.SpELBean).read('书籍')}" name="bookName"/>
    <!-- sp el 通过运算赋值 -->
    <property value="#{1.2}" name="result"/>
</bean>
</beans>

 2.19 基于注解配置Bean【重点】

如果不知道注解是啥可以看一下链接:Java注解(三种JDK内置基本注解、四种元注解的介绍,源码分析!)-CSDN博客

基于注解的方式配置 bean, 主要是项目开发中的组件,比如 Controller Service 、和 Dao.
组件注解的形式有
1. @Component 表示当前注解标识的是一个组件【 是一个通用的标识
2. @Controller 表示当前注解标识的是一个控制器,通常用于 Servlet
3. @Service 表示当前注解标识的是一个处理业务逻辑的类,通常用于 Service
4. @Repository 表示当前注解标识的是一个持久化层的类,通常用于 Dao

 用注解的形式必须使用一个包,将其进行引入在你下载的spring-framework包下

2.19.1快速入门案例 

实例:使用注解的方式来配置 Controller / Service / Respository / Component 

 首先配置四个类(带有其注解的)

MyComponent

package spring.component;

import org.springframework.stereotype.Component;

/**
 * @author sn
 * @Component 标识该类是一个组件, 是一个通用的注解
 */
@Component
public class MyComponent {
}

UserAction 

package spring.component;

import org.springframework.stereotype.Controller;


/**
 * @author sn
 * @version 1.0
 * @Controller 标识该类是一个控制器Controller, 通常这个类是一个Servlet
 */
@Controller
public class UserAction {
 
}

UserService

package spring.component;

import org.springframework.stereotype.Service;

/**
 * @author sn
 * @version 1.0
 * @Service 标识该类是一个Service类/对象
 */
@Service
public class UserService {
    //方法..
    public void hi(){
        System.out.println("UserService hi()~");
    }
}

UserDao

package spring.component;

import org.springframework.stereotype.Repository;

/**
 * @author sn
 * @version 1.0
 * 使用 @Repository 标识该类是一个Repository是一个持久化层的类/对象
 * 1. 标记注解后,类名首字母小写作为id的值(默认)
 * 2. value = "hspUserDao" 使用指定的 hspUserDao作为UserDao对象的id
 */
@Repository
public class UserDao {
}

 测试类

  @Test
    public void setBeanByAnnotation()
    {
        //先获取容器
        ApplicationContext ioc = new ClassPathXmlApplicationContext("beans05.xml");
        //通过类型去获取
        UserAction userAction = ioc.getBean(UserAction.class);
        UserDao userDao = ioc.getBean(UserDao.class);
        UserService userService = ioc.getBean(UserService.class);
        //通过id名进行获取
        MyComponent myComponent = ioc.getBean("myComponent", MyComponent.class);
        System.out.println(myComponent+"\n" + userAction + "\n" +
                userService + "\n" + userDao);
    }

beans.xml

 配置容器要扫描的包
1. component-scan 要对指定包下的类进行扫描, 并创建对象到容器
2. base-package 指定要扫描的包
3. 含义是当spring容器创建/初始化时,就会扫描spring.component包下的所有的 有注解 @Controller / @Service / @Respository / @Component类将其实例化,生成对象,放入到ioc容器。

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--配置容器要扫描的包-->
<!--
配置容器要扫描的包
 1. component-scan 要对指定包下的类进行扫描, 并创建对象到容器
 2. base-package 指定要扫描的包
 3. 含义是当spring容器创建/初始化时,就会扫描spring.component包下的所有的 有注解 @Controller / @Service / @Respository / @Component类将其实例化,生成对象,放入到ioc容器
-->
    <context:component-scan base-package="spring.component"/>
</beans>

debug展示 

2.19.2 细节分析 

@1. 需要导入 spring-aop-5.3.8.jar , 别忘了

@2. 必须在 Spring 配置文件中指定 " 自动扫描的包 " IOC 容器才能够检测到当前项目中哪
些类被标识了注解, 注意到导入 context 名称空间
<!-- 配置自动扫描的包 -->
<context:component-scan base-package="spring.component" />
可以使用通配符 * 来指定 ,比如 spring.* 表示
-- 提问 : spring.component 会不会去扫描它的子包 ?
答:会的
3. Spring IOC 容器不能检测一个使用了 @Controller 注解的类到底是不是一个真正的控
制器。注解的名称是用于程序员自己识别当前标识的是什么组件。其它的 @Service
@Repository 也是一样的道理 [ 也就是说 spring IOC 容器只要检查到注解就会生成对象, 但是这个注解的含义 spring 不会识别,注解是给程序员编程方便看的 ], 也就是说spring容器会根据注解创建对象,他自己确不知道注解的含义
4.
<context:component-scan base-package="spring.component"
resource-pattern="User*.class" />
resource-pattern="User*.class": 表示只扫描User开头的类。
扫描.class是因为在运行时实际扫描的是out目录下的文件,这些文件被编译成了字节码文件
[ 使用的少 ,不想扫描,不写注解就可以 , 知道这个知识点即可 ]
@5 对于要排除的类,可以按形式进行:

需求:如果我们希望排除某个包/子包下的某种类型的注解,可以通过exclude-filter来指定
1. context:exclude-filter 指定要排除哪些类
2. type 指定排除方式 annotation表示按照注解来排除
3. expression="org.springframework.stereotype.Service" 指定要排除的注解的全路径 

 <!--需求:如果我们希望排除某个包/子包下的某种类型的注解,可以通过exclude-filter来指定 
    1. context:exclude-filter 指定要排除哪些类 
    2. type 指定排除方式 annotation表示按照注解来排除 
    3. expression="org.springframework.stereotype.Service" 指定要排除的注解的全路径 -->
    <context:component-scan base-package="spring.component">
    <context:exclude-filter expression="org.springframework.stereotype.Service" type="annotation"/>
    <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
    <context:exclude-filter expression="org.springframework.stereotype.Repository" type="annotation"/>
    </context:component-scan>

@6 可以指定要自动扫描那些类 YU @5相反

1. use-default-filters="false": 不再使用默认的过滤机制
2. context:include-filter: 表示只是扫描指定的注解的类
3. expression="org.springframework.stereotype.Controller": 注解的全类名
<context:component-scan base-package="spring.component" use-default-filters="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Service"/>
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

@ 7. 默认情况:标记注解后,类名首字母小写作为 id 的值。也可以使用注解的 value 属性

指定 id 值,并且 value 可以省略。
@Controller(value="userAction2")
@Controller("userAction2")

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部