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

目录

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;}@Overridepublic 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>
    @Testpublic 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>

测试代码

   @Testpublic 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>

测试代码 

    @Testpublic 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>

测试类 

@Testpublic 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 都是 Stringprivate 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;}@Overridepublic 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对象/javabean2.在beans中可以配置多个bean3.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>

测试文件 

 @Testpublic void setBeanByList(){//先获取容器ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");Master bean = ioc.getBean("master", Master.class);System.out.println("master=>"+bean);}@Testpublic void setBeanByMap(){//先获取容器ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");Master bean = ioc.getBean("master2", Master.class);System.out.println("master=>"+bean);}@Testpublic void setBeanBySet(){//先获取容器ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");Master bean = ioc.getBean("master3", Master.class);System.out.println("master=>"+bean);}@Testpublic void setBeanByArray(){//先获取容器ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");Master bean = ioc.getBean("master4", Master.class);System.out.println("master=>"+bean);}@Testpublic 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;}@Overridepublic 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;}@Overridepublic String toString() {return "Emp{" +"name='" + name + '\'' +", dept=" + dept +'}';}
}

测试类

  @Testpublic 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 指定使用哪个实例工厂对象返回bean2. factory-method 指定使用实例工厂对象的哪个方法返回bean3. 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就是要获取的对像的keyprivate 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;}@Overridepublic Monster getObject() throws Exception {return monster_map.get(key);}@Overridepublic Class<?> getObjectType() {return Monster.class;}@Overridepublic 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属性是 singleton2. 在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="会生孩"/>

测试代码

    @Testpublic 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>
    @Testpublic 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*/@Overridepublic 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*/@Overridepublic 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 容器配置文件 配置了 MyBeanPostProcessor2. 这时后置处理器对象,就会作用在该容器创建的Bean对象3. 已经是针对所有对象编程->切面编程AOP --><bean id="myBeanPostProcessor" class="spring.bean.MyBeanPostProcessor"/></beans>

测试类 

    @Testpublic 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 Problem2. 提示错误,将光标放在context 输入alt+enter 就会自动引入namespace3. location="classpath:my.properties" 表示指定属性文件的位置4. 提示,需要带上 classpath5. 属性文件有中文,需要将其转为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 {//属性OrderServiceprivate OrderService orderService;//getterpublic OrderService getOrderService() {return orderService;}//setterpublic 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;//getterpublic OrderDao getOrderDao() {return orderDao;}//setterpublic void setOrderDao(OrderDao orderDao) {this.orderDao = orderDao;}
}

 OrderDao

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

 测试类

  @Testpublic 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.mzph.cn/news/882750.shtml

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

相关文章

骨传导耳机哪款好?五大热门畅销骨传导耳机推荐!

在当今快节奏的生活中&#xff0c;骨传导耳机因其独特的声音传导方式和开放式的佩戴体验&#xff0c;逐渐成为运动爱好者和音乐发烧友的新宠。它们不仅提供了一种更为安全、舒适的听觉享受&#xff0c;还能在运动时让我们保持对周围环境的感知。随着技术的不断进步&#xff0c;…

理解VSCODE基于配置的设置,避免臃肿

这节课我们讲两点&#xff1a; &#xff08;一&#xff09;下载、安装、汉化及美化 VSCODE&#xff1b; &#xff08;二&#xff09;理解VSCODE中基于配置&#xff08;Profiles&#xff09;的设置&#xff08;Settings&#xff09;&#xff0c;让 VSCODE 保持清爽。 &#xff0…

Java:数据结构-二叉树oj题

1.判断两个数是否相同 题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; public boolean isSameTree(TreeNode p, TreeNode q) {if(pnull && q!null || qnull && p!null){return false;}if(pnull && qnull){return true;}if(q.val!p.v…

跨越数字鸿沟,FileLink文件摆渡系统——您的数据安全高效传输新选择

在这个信息爆炸的时代&#xff0c;数据的流通与共享已成为推动各行各业发展的关键力量。然而&#xff0c;随着数据量的激增&#xff0c;如何在保证数据安全的前提下&#xff0c;实现高效、便捷的文件传输&#xff0c;成为了众多企业和个人用户面临的重大挑战。正是在这样的背景…

zabbix 迁移数据目录

由于安装zabbix的时候数据目录给小了&#xff0c;现在决定迁移数据目录 一&#xff1a;查找数据目录 这个数据目录我们只需要看数据库的配置文件就行&#xff0c;my,cnf datadir指向的就是数据目录 ls /var/lib/mysql/ 二&#xff1a;创建新的数据目录 mkdir /monitor/ …

大数据实验3: HDFS基础编程 (shell命令、JAVA API使用)

实验3&#xff1a; HDFS基础编程 一、实验目的 HDFS的shell命令使用HDFS的JAVA API使用&#xff1b; 二、实验平台 操作系统&#xff1a;Linux&#xff08;Ubuntu16.04&#xff09;&#xff1b;Hadoop版本&#xff1a;3.3.1&#xff1b;JDK版本&#xff1a;1.8&#xff1b;…

C++20中头文件source_location的使用

<source_location>是C20中新增加的头文件&#xff0c;此头文件是utility库的一部分。 主要内容为类std::source_location&#xff1a;表示有关源代码的某些信息&#xff0c;例如文件名(__FILE__)、行号(__LINE__)和函数名(__func__)。 以下为测试代码&#xff1a; names…

交易之路:如何找到适合自己的交易品种

大部分新手交易者最容易陷入的误区就是盲目跟风&#xff0c;他们倾向于选择那些被众人追捧且看似成功的交易品种&#xff0c;认为既然大家都在做&#xff0c;那么一定有利可图。然而&#xff0c;他们忽略了交易品种选择的核心原则&#xff1a;基于个人的深入测试与理解&#xf…

传统企业营销新起点:百科词条构建基础策略!

合作咨询联系竑图 hongtu201988 搜索你的企业名称&#xff0c;出现的结果是什么&#xff1f;是否大部分都是信用网站的基础注册信息&#xff1f;没有正面的企业形象展示&#xff1f; 如果企业做了百度词条呢&#xff1f;会是一个什么结果呢&#xff1f; 以上两种结果带给大家的…

百度智能云千帆 ModelBuilder 大模型服务及开发解读

本文整理自百度云智峰会 2024 —— 大模型平台技术实践论坛的同名演讲。 更多大会演讲内容&#xff0c;请访问&#xff1a; https://cloud.baidu.com/summit/AIcloudsummit_2024/index.html 最近大模型产业应用圈子里有一句非常流行的话&#xff0c;叫做度日如年。不是说这件…

自动化检查网页的TDK,python+selenium自动化测试web的网页源代码中的title,Description,Keywords

首先&#xff0c;TDK是什么&#xff1f;对于新手小白来说&#xff0c;可能是懵逼的&#xff0c;所以这里给出一个官方的解说‌网页的TDK是指标题&#xff08;Title&#xff09;、描述&#xff08;Description&#xff09;和关键词&#xff08;Keywords&#xff09;的集合‌。这…

【服务器】服务器 BMC(基板管理控制器,Baseboard Management Controller)

基板管理控制器&#xff08;BMC&#xff0c;Baseboard Management Controller&#xff09;是用于监控和管理服务器的专用控制器&#xff0c;用通俗的话讲&#xff0c;BMC 是主机服务器系统下的一个独立系统。这个独立系统有自己的处理器和内存&#xff0c;即使主机硬件或操作系…

开源限流组件分析(一):juju/ratelimit

文章目录 本系列前言数据结构对外提供接口初始化令牌桶获取令牌 核心方法adjustavailableTokenscurrentTicktakeTakeAvailableWait系列 本系列 开源限流组件分析&#xff08;一&#xff09;&#xff1a;juju/ratelimit&#xff08;本文&#xff09;开源限流组件分析&#xff0…

Race Track Generator Ultimate:Race Track Generator(赛车场赛道看台场景创建工具)

下载&#xff1a;​​Unity资源商店链接资源下载链接 效果图&#xff1a;

【论文阅读】Bi-Mamba+: Bidirectional Mamba for Time Series Forecasting

文章目录 概要阅读背景知识引言创新之处 研究方法概述方法部分的核心模块多尺度打补丁&#xff08;Multi-Scale Patching&#xff09;Mamba&#xff1a;全局模式专家Local Window Transformer&#xff08;LWT&#xff09;&#xff1a;局部变化专家长短期路由器&#xff08;Long…

Bootstrap Blazor实现多个Select选择器联合选择

Bootstrap Blazor官方目前只提供单个Select选择器&#xff0c;如果要想实现下图所示的多个Select选择器联合选择&#xff0c;则需要通过编写自定义组件来实现。 主要通过Bootstrap的data-bs-toggle属性来实现展开和折叠效果。 .razor文件内容如下&#xff1a; typeparam TValu…

【路径规划】蚁群算法的优化计算——旅行商问题(TSP)优化

摘要 旅行商问题&#xff08;TSP&#xff09;是一种经典的组合优化问题&#xff0c;其目标是找到一条遍历所有城市且总路程最短的环路。由于其计算复杂度高&#xff0c;求解大规模TSP问题往往依赖于启发式算法。本文研究了基于蚁群算法&#xff08;Ant Colony Optimization, A…

034_基于php万怡酒店管理系统

目录 系统展示 开发背景 代码实现 项目案例 获取源码 博主介绍&#xff1a;CodeMentor毕业设计领航者、全网关注者30W群落&#xff0c;InfoQ特邀专栏作家、技术博客领航者、InfoQ新星培育计划导师、Web开发领域杰出贡献者&#xff0c;博客领航之星、开发者头条/腾讯云/AW…

python之数据结构与算法(数据结构篇)-- 字典

一、字典的概念 这里我使用“小羊们”举例子&#xff0c;现在我需要去创建一个"羊村小羊们的身高"字典去保存小羊们的身高&#xff0c;对小羊们的身高进行查询、增加、删除、遍历等一系列操作。去更好的理解&#xff0c;字典是个什么东东&#xff01;&#xff01;&…

Java根据word 模板,生成自定义内容的word 文件

Java根据word 模板&#xff0c;生成自定义内容的word 文件 背景1 使用技术2 实现方法依赖啊 3 问题4 背景 主要是项目中需要定制化一个word&#xff0c;也就是有一部分是固定的&#xff0c;就是有一个底子&#xff0c;框架&#xff0c;里面的内容是需要填充的。然后填充的内容…