Spring配置/管理bean-IOC(控制反转) 非常详细!基于XML及其注解!案例分析! 建议复习收藏!

news2024/10/23 19:55:21

目录

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2221828.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AWD的复现

学习awd的相关资料&#xff1a;速成AWD并获奖的学习方法和思考记录- Track 知识社区 - 掌控安全在线教育 - Powered by 掌控者&#xff08;包含使用脚本去批量修改密码&#xff09; 在复现之前去了解了以下AWD的相关脚本 资料&#xff1a;AWD批量攻击脚本使用教程-CSDN博客 …

网络安全有关法律法规

1. 前言 在当今数字化高速发展的时代&#xff0c;网络安全已成为关乎国家、企业和个人的重要议题。为了应对日益复杂的网络安全挑战&#xff0c;一系列网络安全法律法规应运而生&#xff0c;它们如同坚实的盾牌&#xff0c;守护着我们的数字世界。现在是2024年10月&#xff0c…

军团服务QA角度总结

需求背景&#xff1a; 军团业务诞生的时候承接家族群组功能&#xff0c;玩法邀请成员做任务->积分升级->发送奖励。还是拉收入的一个业务载体。收入才是王道。 军团服务端核心就三个&#xff1a;军团创建&#xff0c;人员管理和军团奖励。 军团创建&#xff1a; 创建…

每天练打字8:今日状况——常用字后五百击键4.5第1遍进行中,赛文速度105.75

今日跟打&#xff1a;738字 总跟打&#xff1a;125701字 记录天数&#xff1a;2459天 &#xff08;实际没有这么多天&#xff0c;这个是注册账号的天数&#xff09; 平均每天&#xff1a;50字 本周目标完成进度&#xff1a; 练习常用单字后500&#xff0c;击键3.5&#xff0c;…

kernel32.dll的功能、作用,教大家几种修复kernel32.dll错误的办法

当这个文件出现问题时&#xff0c;用户可能会遇到各种错误消息&#xff0c;例如“缺失kernel32.dll”或“kernel32.dll发生错误”。这些错误不仅令人困扰&#xff0c;还可能威胁到您的数据安全和系统性能。接下来&#xff0c;本文将教大家几种修复kernel32.dll错误的有效方法&a…

群控系统服务端开发模式-业务流程图补充

进天有读者给我反馈&#xff0c;业务流程图看的不是很明确&#xff0c;所以我把未画完的业务流程图补充完毕。也希望以后更多的读者给我评论及意见。 一、业务流程梳理 1、非业务流程 a、添加部门、添加级别、添加执行方式。因为这些参数都是要被其他地方调用的&#xff0c;更…

word中的内容旋转90度

在vsto、Aspose.Words 中&#xff0c;默认没有直接的 API 可以让表格整体旋转 90 度。然而&#xff0c;我们可以通过一些方式来实现类似的效果&#xff0c;具体思路如下&#xff1a; 将表格插入到一个形状&#xff08;Shape&#xff09;或文本框中&#xff0c;然后旋转该形状。…

影刀RPA实战番外:excel函数应用指南

Excel函数是用于执行特定计算、分析和数据处理任务的预定义公式。它们可处理数学计算、文本处理、逻辑判断、日期和时间运算、查找和引用数据等。例如&#xff0c;SUM函数可以计算一系列数字的总和&#xff0c;IF函数进行逻辑测试&#xff0c;VLOOKUP函数在表格中查找数据&…

Oracle CONNECT BY、PRIOR和START WITH关键字详解

Oracle CONNECT BY、PRIOR和START WITH关键字详解 1. 基本概念2. 数据示例3. SQL示例3.1. 查询所有员工及其上级3.2. 显示层次结构3.3. 查询特定员工的子级 4. 结论 在Oracle数据库中&#xff0c;CONNECT BY、PRIOR和START WITH关键字主要用于处理层次结构数据&#xff0c;例如…

我悟了,华为FreeBuds 6i这样戴更稳了!

谁懂啊&#xff0c;才知道华为FreeBuds 6i标配多种尺寸的耳塞&#xff08;如S、M、L&#xff09;&#xff0c;方便大家根据自己耳道大小自由选择。如果耳机戴上后感到耳朵不适或松动&#xff0c;可能是耳塞尺寸不匹配。 小提示&#xff1a; 耳塞过大 可能会造成压迫感&#xf…

kafka自定义配置信息踩坑

org.apache.kafka.common.config.ConfigException: Invalid value 0 for configuration acks: Expected value to be a string, but it was a java.lang.Integer 场景描述&#xff1a; 单个kafka使用springboot框架自带的 yml 配置完全OK&#xff08;因为底层会帮我们处理好类…

CSS 设置网页的背景图片

背景 最近正好在写一个个人博客网站“小石潭记”&#xff0c;需要一张有水&#xff0c;有鱼的图片。正好玩原神遇到了类似场景&#xff0c;于是截图保存&#xff0c;添加到网站里面。以下是效果图&#xff1a; css 写个class&#xff0c;加到整个网页的body上 .bodyBg {ba…

接口测试 —— 如何测试加密接口?

接口加密是指在网络传输过程中&#xff0c;将数据进行加密&#xff0c;以保护数据的安全性。接口加密可以采用多种加密算法&#xff0c;如AES、DES、RSA等。测试接口加密的目的是验证接口加密算法的正确性和安全性。以下是一些详细的测试方法和注意事项&#xff1a; 接口加密字…

A-【项目开发知识管理】Android AIDL跨进程通信

Android AIDL跨进程通信 文章目录 Android AIDL跨进程通信0.我为啥要写这篇文章1.AIDL是干啥的&#xff1f;1.1简述1.2官方话 2.在AndroidStudio中怎么干&#xff1f;2.1准备工作2.2在项目A中创建AIDL文件夹2.3在项目A中创建一个aidl文件2.4将项目A进行一次Rebuild操作2.5在项目…

计算机专业大学四年的学习路线(非常详细),零基础入门到精通,看这一篇就够了

前言 许多学子选择踏上计算机这条充满挑战与机遇的道路。但在大学四年中&#xff0c;如何规划自己的学习路线&#xff0c;才能在毕业时脱颖而出&#xff0c;成为行业的佼佼者呢&#xff1f; 第一学年&#xff1a;基础知识的奠基 1.1 课程安排 在大学的第一年&#xff0c;重…

超详解C++类与对象(下)

目录 1. 初始化列表 1.1. 定义 2.2. 注意 2. 隐式类型转换 2.1. 内置类型 2.2. 自定义类型 2.3. explicit关键字 3.类的静态成员 2.1. 定义 2.2. 注意 4.const成员函数 5. 友元 5. 1友元函数 5.2. 友元类 6. 内部类 6.1. 定义 6.2. 注意 7. 匿名对象 7…

手撕布隆过滤器:原理解析与面试心得

前言 说来话长&#xff0c;话来说长。前些天我投了一些日常实习的简历&#xff0c;结果足足等了两个礼拜才收到面试通知&#xff0c;看来如今的行情确实是挺紧张的。当时我是满怀信心去的&#xff0c;心想这次一定要好好拷打面试官一番&#xff0c;结果没想到&#xff0c;自我…

一、python基础

python基础 认识Python1. Python介绍1.1 为什么学习Python1.2 Python发展历史 2. 语言分类简介2.1 编译型2.2 解释型 Python环境搭建1. Python 解释器1.1 Python解释器下载1.2 Python解释器安装 2. 解释器运行Python脚本2.1 演练步骤 PyCharm1. PyCharm介绍2. PyCharm安装3. Py…

15分钟学Go 第6天:变量与常量

第6天&#xff1a;变量与常量 在Go语言中&#xff0c;变量和常量是编程的基础概念。理解如何定义和使用它们不仅能帮助我们管理数据&#xff0c;还能增强代码的可读性和可维护性。在本章中&#xff0c;我们将详细探讨Go语言中的变量和常量&#xff0c;涵盖它们的定义、使用、作…

机器学习建模分析

机器学习 5.1 机器学习概述5.1.1 机器学习与人工智能5.1.2 python机器学习方法库 5.2 回归分析5.2.1 回归分析原理5.2.2 回归分析实现 5.3 分类分析5.3.1 分类学习原理5.3.2 决策树5.5.3 支持向量机 5.4 聚类分析5.4.1 聚类任务5.4.2 K-means算法 5.5 神经网络和深度学习5.5.1神…