Bean注入 | xml配置文件
Bean配置
别名配置
xml
<!--设置别名:在获取Bean的时候可以使用别名获取,原名依旧可用-->
<alias name="userT" alias="userNew"/>
xml
<!--bean就是java对象,由Spring创建和管理-->
<!--
id 是bean的标识符,要唯一
- 如果没有配置id,name就是默认标识符
- 如果配置id,又配置了name,那么name是别名。name可以设置多个别名,可以用逗号、分号、空格等隔开
如果不配置id和name,可以根据applicationContext.getBean(.class)获取对象;
class是bean的全限定名=包名+类名
-->
<bean id="hello" name="hello2 h2,h3;h4" class="com.kuang.pojo.Hello">
<property name="name" value="Spring"/>
</bean>
多xml配置文件管理
xml
<!--在主配置文件中,引入其他配置文件,可以将其他配置文件中配置的Bean导入。分开来写配置文件,结构更清晰-->
<import resource="{path}/beans.xml"/>
DI | 通过属性注入
Bean属性的写入,本质是依赖于类的set()方法。通过无参构造器创建对象,并通过属性的set()方法完成属性写入。
常见属性类型的set方式注入:
java
public class Student {
// 属性
private String name;
private Address address;
private String[] books;
private List<String> hobbys;
private Map<String,String> card;
private Set<String> games;
private String wife;
private Properties info;
// set方法:......
public void show(){
System.out.println("name="+ name
+ ",address="+ address.getAddress()
+ ",books="
);
for (String book:books){
System.out.print("<<"+book+">>\t");
}
System.out.println("\n爱好:"+hobbys);
System.out.println("card:"+card);
System.out.println("games:"+games);
System.out.println("wife:"+wife);
System.out.println("info:"+info);
}
}
xml
<bean id="addr" class="com.example.Address">
<property name="address" value="重庆"/>
</bean>
<bean id="student" class="com.example.Student">
<!--常量注入-->
<property name="name" value="小明"/>
<!--bean注入-->
<property name="address" ref="addr"/>
<!--数组注入-->
<property name="books">
<array>
<value>西游记</value>
<value>红楼梦</value>
<value>水浒传</value>
</array>
</property>
<!--list注入-->
<property name="hobbys">
<list>
<value>听歌</value>
<value>看电影</value>
<value>爬山</value>
</list>
</property>
<!--map注入-->
<property name="card">
<map>
<entry key="中国邮政" value="456456456465456"/>
<entry key="建设" value="1456682255511"/>
</map>
</property>
<!--集合set注入-->
<property name="games">
<set>
<value>LOL</value>
<value>BOB</value>
<value>COC</value>
</set>
</property>
<!--null值注入-->
<property name="wife"><null/></property>
<!--properties注入-->
<property name="info">
<props>
<prop key="学号">20190604</prop>
<prop key="性别">男</prop>
<prop key="姓名">小明</prop>
</props>
</property>
</bean>
补充:上述Bean注入有另外一种形式,inner bean注入。示例如下:
xml
<bean id="student2" class="com.example.Student">
<!--常量注入-->
<property name="name" value="小明"/>
<!--inner_bean注入-->
<property name="address">
<bean class="com.example.Address">
<property name="address" value="上海"/>
</bean>
</property>
<!--其余的属性......-->
</bean>
DI | 通过构造器注入
属性的写入,本质是构造器方式注入
java
public class UserT {
private String name;
public UserT(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name="+ name );
}
}
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">
<!-- 第一种根据index参数下标设置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
<!-- index指构造方法 , 下标从0开始 -->
<constructor-arg index="0" value="kuangshen2"/>
</bean>
<!-- 第二种根据参数名字设置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
<!-- name指参数名 -->
<constructor-arg name="name" value="kuangshen2"/>
</bean>
<!-- 第三种根据参数类型设置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
<constructor-arg type="java.lang.String" value="kuangshen2"/>
</bean>
</beans>
第三种方法使用较为限制。当多个属性具有相同的类型,就没法用了。其中type的相关写法有如下标准:
- type是基本数据类型,就写:int、double...
- type是引用数据类型,就按照上边示例来写就行
java
@Test
public void testT(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 在配置文件加载的时候。其中管理的对象都已经初始化了!
UserT user = (UserT) context.getBean("userT");
user.show();
}
DI | p标签、c标签注入
-
p标签注入的本质是:属性注入,需要有无参构造方法+set()方法
-
c标签注入的本质是:构造器注入,需要有响应的带参构造方法
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 id="user" class="com.kuang.pojo.User" p:name="狂神" p:age="18"/>
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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--需要在头部导入c标签约束:上述倒数第三行-->
<bean id="user" class="com.kuang.pojo.User" c:name="狂神" c:age="18"/>
Bean属性装配 | autowire
自动装配是Spring满足bean依赖的一种方式。不需要手动给与属性,Sping会在上下文中自动寻找,并自动给bean装配属性
示例
一个人,有名字和两个宠物,分别是猫和狗,都会叫:猫会miao,狗会wang
分析:
- 3个bean:狗、猫、人
- 狗的bean:"叫"方法
- 猫的bean:"叫"方法
- 人的bean:三个属性,名字、狗、猫
java
public class Cat {
public void shout() {
System.out.println("miao~");
}
}
java
public class Dog {
public void shout() {
System.out.println("wang~");
}
}
java
package com.learn.Hello;
public class People {
private Cat cat;
private Dog dog;
private String name;
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
常规case:手动装配Bean的属性
xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--猫-->
<bean id="cat" class="com.learn.Hello.Cat"/>
<!--狗-->
<bean id="dog" class="com.learn.Hello.Dog"/>
<!--人-->
<bean id="People" class="com.learn.Hello.People">
<property name="name" value="张三"/>
<property name="dog" ref="dog"/>
<property name="cat" ref="cat"/>
</bean>
</beans>
autowire装配Bean属性:byName
通过byName方式自动装配属性:会自动在上下文中查找id跟自己属性值一样的bean
xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--猫-->
<bean id="cat" class="com.learn.Hello.Cat"/>
</bean>
<!--狗-->
<bean id="dog" class="com.learn.Hello.Dog"/>
</bean>
<!--人-->
<bean id="People" class="com.learn.Hello.People" autowire="byName">
<property name="name" value="张三"/>
</bean>
</beans>
- 将cat的id改为catXXX,报错
autowire装配Bean属性:byType
通过byType的方式自动装配属性:会根据属性的类型,自动去上下文中找对应属性的bean,这就要求该属性的bean全局唯一,不然idea会报错
xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--猫-->
<bean id="cat" class="com.learn.Hello.Cat">
</bean>
<!--狗-->
<bean id="dog" class="com.learn.Hello.Dog">
</bean>
<!--人-->
<bean id="People" class="com.learn.Hello.People" autowire="byType">
<property name="name" value="张三"/>
</bean>
</beans>
- case1:再注册一个cat对象,bean id取名为cat2,报错【因为拥有cat类型的bean不唯一】
- case2:将cat和dog的id删除掉,运行,正常【因为是通过Type进行自动装配的,不影响结果】
Bean注入 | 注解
属性装配 | @Autowired
该注解可以不需要Bean中有set方法。是Spring在创建bean的时候,通过检测
@Autowired
注解来装配bean的依赖关系。该注解默认是根据byType方式注入依赖的
该注解是Spring框架默认的注解
示例:
java
// 字段上加入注解
public class People {
@Autowired
private Cat cat;
@Autowired
private Dog dog;
private String name;
// 相关的set、get方法
}
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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--开启注解扫描,支持注解的方式装配bean依赖-->
<context:annotation-config/>
<!--猫-->
<bean id="cat" class="com.learn.Hello.Cat"/>
<!--狗-->
<bean id="dog" class="com.learn.Hello.Dog"/>
<!--人-->
<bean id="people" class="com.learn.Hello.People"/>
</beans>
该注解可以用在:字段上、构造器上、set()方法上、方法的参数上(配合@Bean使用)。示例如下:
java
// 字段上
@Autowired
private MyService myService;
// 构造器上
@Autowired
public MyComponent(MyService myService) {
this.myService = myService;
}
// set方法上
private MyService myService;
@Autowired
public void setMyService(MyService myService) {
this.myService = myService;
}
// 方法参数上。这里的@Autowired注解不是必须的,可以省略,因为在@Bean注解下的参数中省略@Autowired注解,spring会尝试自动装配。
@Bean
public MyComponent myComponent(@Autowired MyService myService) {
return new MyComponent(myService);
}
该注解也可以有相关参数:
java
// required=false,即对象可以为null;该参数默认为true,即注解的属性不可以为null
public class People {
@Autowired(required=false)
private Cat cat;
}
属性装配 | @Qualifier
@Autowired是根据类型(Type)自动装配的,当根据类型无法完成装配时,加上@Qualifier则可以根据byName的方式自动装配
@Qualifier不能单独使用,需要和@Autowired配套使用
需要明确的是,两者搭配,依旧是:先按照byType的方式匹配,匹配不到的话再按照byName的方式匹配
该注解是Spring框架默认的注解
xml
<bean id="dog1" class="com.kuang.pojo.Dog"/>
<bean id="dog2" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>
<bean id="cat2" class="com.kuang.pojo.Cat"/>
java
package com.learn.Hello;
import org.springframework.beans.factory.annotation.Autowired;
public class People {
@Autowired()
@Qualifier(value = "cat2")
private Cat cat;
@Autowired
@Qualifier(value = "dog2")
private Dog dog;
private String name;
public Cat getCat() {
return cat;
}
public Dog getDog() {
return dog;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
属性装配 | @Resource
不是Spring框架的注解,而是Java自带的注解
@Resource注解如果没有指定参数:先按照默认的byName方式查找bean,找不到再按照byType方式查找bean
@Resource注解如果指定了参数:
- 指定了name参数:匹配特定名字的bean,没有的话就抛出异常
- 指定了type属性:匹配特定属性的bean,匹配不到的话(没有或有多个)抛出异常
xml
<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>
<bean id="cat2" class="com.kuang.pojo.Cat"/>
<bean id="user" class="com.kuang.pojo.User"/>
java
public class User {
//如果允许对象为null,设置required = false, 默认为true
@Resource(name = "cat2")
private Cat cat;
@Resource
private Dog dog;
private String str;
}
@Autowired、@Qualifier、@Resource总结
注解方法 | 解释 | 可用于 |
---|---|---|
@Autowired | 默认按类型装配 | 字段、构造器、set方法、方法参数 |
@Qualifier | 按照指定name装配,配合@Autowired使用,不可单独使用 | 字段、构造器、set方法、方法参数 |
@Resource | 无参数指定:默认按照名称进行装配,然后按照类型装配 可进行参数指定:指定name 或 指定type | 字段、set方法 |
@Component、@Value、@scope
从基于xml文件的bean标签实现bean创建和依赖注入,到通过@Component、@Value、@scope注解形式实现bean创建和依赖注入
beans.xml文件配置
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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--指定扫描哪些包上的注解:扫描的是包下面类上的注解,而不是扫描方法上的注解-->
<context:component-scan base-package="com.kuang.pojo"/>
<!--允许通过注解注入bean-->
<context:annotation-config/>
</beans>
指定包下编写类,并加入注解
java
@Component("user") // 相当于配置文件中 <bean id="user" class="com.spring.learn.User"/>
@Scope("prototype") // 相当于配置文件中 <bean id="user" class="com.spring.learn.User" scope="prototype"/>
public class User {
@Value("张三") // 写在字段上:相当于配置文件中 <property name="name" value="张三"/>
public String name;
public int age;
@Value(18) // 写在set方法上:相当于配置文件中 <property name="age" value="张三"/>
public void setAge(int age) {
this.age = age;
}
}
测试
java
@Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
User user = (User) applicationContext.getBean("user");
System.out.println(user.name);
}
@Component衍生注解
为了更好的进行分层,表示该类属于哪个层下面。Spring可以使用其它三个注解,功能跟@Component都一样
注解 | 应用场景 |
---|---|
@Controller | 在Controller层进行注入时使用的注解 |
@Service | 在Service层进行注入时使用的注解 |
@Repository | 在Dao层进行注入时使用的注解 |
xml与注解的区别
XML | 注解 |
---|---|
可以适用任何场景 ,结构清晰,维护方便 | 注解只能对特定的类生效,开发简单方便 |
@Configuration、@ComponentScan
JavaConfig 原来是 Spring 的一个子项目,它通过 Java 类的方式提供 Bean 的定义信息,在 Spring4 的版本, JavaConfig 已正式成为 Spring4 的核心功能
这两个注解配合使用,可以使得:从原先的xml文件配置Bean并注入依赖,改为仅通过Java类配置Bean并完成依赖注入
示例
java
@Component // 可以创建一个id=dog的Bean,并放入到IOC容器中
public class Dog {
public String name = "dog";
}
java
//代表这是一个配置类,用来定义Bean的
@Configuration
// 代表要扫描Dog包下的类,带有@Component注解的类将创建bean,并放进Spring容器中管理
// 如果没有该注解,会默认扫描@Configuration的类所在的包
@ComponentScan("com.learn.Dog")
public class MyConfig {
@Bean //通过方法注册一个bean,这里的返回值就Bean实例,方法名就是bean的id!
public Dog getDog(){
return new Dog();
}
}
java
@Test
public void test2(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
Dog dog = (Dog) applicationContext.getBean("getDog");
System.out.println(dog.name);
}
总结
@ComponentScan 和 @Configuration 一般配合一起使用
-
如果没有@ComponentScan,会默认扫描@Configuration所注解的类所在的包
-
但为什么要配合使用?
如果类中用了@Controller,@Repository,@Service, @Component四大注解标识之一了,那么如果不加上@ComponentScan,Spring就不会自动扫描类上的四大注解中的任何一个,那么四大注解下的类就不会被Spring扫描到,更不会装入Spring容器中,注解就失去了作用。