什么是bean的装配
指的是用户将自己开发的Bean装配到Spring Ioc容器中
Bean的装配方式1----在XML文件中显式装配
- 简易值的装配
指的是一般数据类型的装配;比如说Integer、String等;可以参考上一篇博客 - 集合装配
Set、Map、List、Array、Properties
<bean id="favorite1" class="com.bean.Favorite">
<property name="favoriteName" value="踢球"/>
</bean>
<bean id="user1" class="com.bean.User">
<property name="id" value="1"/>
<property name="name" value="刘飞红"/>
<property name="employee" value="总经理"/>
<property name="favorite" ref="favorite1"/>
</bean>
<!--
<bean id="favorite2" class="com.bean.Favorite">
<constructor-arg index="0" value="篮球"/>
</bean>
<bean id="user2" class="com.bean.User">
<constructor-arg index="0" value="2"/>
<constructor-arg index="1" value="刘颖"/>
<constructor-arg index="2" value="部门经理"/>
<constructor-arg index="3" ref="favorite2"/>
</bean>
-->
<bean id="special" class="com.bean.SpecialLoad" >
<property name="set">
<set>
<value>set-value1</value>
<value>set-value3</value>
</set>
</property>
<property name="map">
<map>
<entry key="map-key1" value="map-value1"/>
<entry key="map-key2" value="map-value2"/>
</map>
</property>
<property name="list">
<list>
<value>list-value-1</value>
<value>list-value-2</value>
</list>
</property>
<property name="array">
<array>
<value>array-value1</value>
<value>array-value2</value>
</array>
</property>
<property name="properties">
<props>
<prop key="prop1">prop-value-1</prop>
<prop key="prop2">prop-value-2</prop>
</props>
</property>
<property name="userList" ref="user1"/>
</bean>
</beans>
- 命名空间的装配(一般不使用)
a、必须引入对应的命名空间和xml模式文件
例如:
<bean id="role4" class="com.bean.Role" c:_0="1" c:_1="经理" c:_2="部门管理"/>
b、使用构造器注入
Bean的装配方式2----使用@Component装配
隐式Bean的发现机制和自动装配原则
组件扫描:通过定义资源的方式,让Spring Ioc容器扫描对应的包从而把Bean装配进来
最基础的扫描
- 使用@Component装配Bean
package com.bean;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @author Una
* @date 2022/8/8 20:58
* @description:
*/
@Data
@Component(value = "role1")
public class Role {
@Value("1")
private Integer id;
@Value("张飞")
private String name;
@Value("部门经理")
private String emp;
public Role() {
}
public Role(Integer id, String name, String emp) {
this.id = id;
this.name = name;
this.emp = emp;
}
}
2.创建一个配置类,该类使用@ComponentScan注解告诉Ioc容器在什么地方扫描Bean@ComponentScan默认扫描当前包的路径(bean和配置类在同一个包才能扫描到)
package com.bean;
import org.springframework.context.annotation.ComponentScan;
/**
* @author Una
* @date 2022/8/8 21:17
* @description:默认扫描当前包的路径(bean和配置类在同一个包才能扫描到)
*/
//@ComponentScan(basePackageClasses = {Role.class, RoleServiceImpl.class})//(basePackageClasses = {Role.class})可以省略
@ComponentScan(basePackages = {"com.bean"})
//可以扫描包也可以扫描类
public class BuildRole {
}
- 在使用时要用AnnotationConfigApplicationContext类去创建Ioc容器; 在创建Ioc容器时,要将定义的配置类的信息导入;调用getBean()获取
package com.bean;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import static org.junit.Assert.*;
/**
* @author Una
* @date 2022/8/8 21:15
* @description:
*/
public class RoleTest {
@Test
public void selectRole(){
ApplicationContext cp=new AnnotationConfigApplicationContext(BuildRole.class);
Role role=(Role) cp.getBean("role1");
System.out.println(role);
}
}
最终结果:
多文件时的扫描
在很多时候,我们需要实现接口的方法;在方法中;我们使用对象。在这种情况下,往往需要多个文件来实现;bean文件、接口文件、接口实现文件;下面以Role为例使用ComponentScan:
- Role bean文件:
package com.bean;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @author Una
* @date 2022/8/8 20:58
* @description:
*/
@Data
@Component(value = "role1")
public class Role {
@Value("1")
private Integer id;
@Value("张飞")
private String name;
@Value("部门经理")
private String emp;
public Role() {
}
public Role(Integer id, String name, String emp) {
this.id = id;
this.name = name;
this.emp = emp;
}
}
- 接口文件RoleService:
package com.service;
import com.bean.Role;
/**
* @author Una
* @date 2022/8/9 14:22
* @description:
*/
public interface RoleService {
public void printRoleInfo(Role role);
}
- 接口实现类
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
/**
* @author Una
* @date 2022/8/9 14:23
* @description:
*/
@Data
@Component
public class RoleServiceImpl implements RoleService {
@Override
public void printRoleInfo(Role role) {
System.out.println("["+role.getId()+";"+role.getName()+";"+role.getEmp()+"]");
}
}
- 扫描文件
值得注意的是;在扫描文件进行扫描时;需要扫描两个文件或者两个文件所在的包
package com.bean;
import com.impl.RoleServiceImpl;
import org.springframework.context.annotation.ComponentScan;
/**
* @author Una
* @date 2022/8/8 21:17
* @description:默认扫描当前包的路径(bean和配置类在同一个包才能扫描到)
*/
//@ComponentScan(basePackageClasses = {Role.class, RoleServiceImpl.class})//(basePackageClasses = {Role.class})可以省略
@ComponentScan(basePackages = {"com.bean","com.Impl"})
public class BuildRole {
//用RoleServiceImpl.class把Role.class扫描
}
- 测试文件
值得注意的是:在测试时必须使用 AnnotationConfigApplicationContext作为Ioc容器
package com.service;
import com.bean.BuildRole;
import com.bean.Role;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import static org.junit.Assert.*;
/**
* @author Una
* @date 2022/8/9 14:45
* @description:
*/
public class RoleServiceTest {
@Test
public void getRole(){
AnnotationConfigApplicationContext aa=new AnnotationConfigApplicationContext(BuildRole.class);
Role role=aa.getBean(Role.class);
RoleService roleService=aa.getBean(RoleService.class);
roleService.printRoleInfo(role);
}
}
Bean的装配方式3----使用@Autowired自动装配
@Autowired需要配合@Component使用;@Autowired的含义是自动装配;它配合@Component扫描直接将bean注入;下面以Role为例
实现一个接口的情况
- Role类
在Role类中;使用@Component、@Value将Role配置完成
package com.bean;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @author Una
* @date 2022/8/8 20:58
* @description:
*/
@Data
@Component(value = "role1")
public class Role {
@Value("1")
private Integer id;
@Value("张飞")
private String name;
@Value("部门经理")
private String emp;
public Role() {
}
public Role(Integer id, String name, String emp) {
this.id = id;
this.name = name;
this.emp = emp;
}
}
- RoleService接口
在接口中;除了方法;不需要进行别的操作
package com.service;
import com.bean.Role;
/**
* @author Una
* @date 2022/8/9 14:22
* @description:
*/
public interface RoleService {
public void printRoleInfo();
}
- RoleServiceImpl实现RoleService方法
在RoleServiceImpl中;使用@Autowired将配置好的Role对象赋给role
package com.impl;
import com.bean.Role;
import com.service.RoleService;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
/**
* @author Una
* @date 2022/8/9 14:23
* @description:
*/
@Data
@Component
public class RoleServiceImpl implements RoleService {
@Autowired
private Role role=null;
@Override
public void printRoleInfo() {
System.out.println("["+role.getId()+";"+role.getName()+";"+role.getEmp()+"]");
}
}
- 扫描文件BuildRole
可以扫描类文件也可以扫描包
package com.bean;
import com.impl.RoleServiceImpl;
import org.springframework.context.annotation.ComponentScan;
/**
* @author Una
* @date 2022/8/8 21:17
* @description:默认扫描当前包的路径(bean和配置类在同一个包才能扫描到)
*/
//@ComponentScan(basePackageClasses = {Role.class, RoleServiceImpl.class})//(basePackageClasses = {Role.class})可以省略
@ComponentScan(basePackages = {"com.bean","com.Impl"})
public class BuildRole {
//用RoleServiceImpl.class把Role.class扫描
}
- RoleServiceTest测试结果
在测试时;可以不再获得role
package com.service;
import com.bean.BuildRole;
import com.bean.Role;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import static org.junit.Assert.*;
/**
* @author Una
* @date 2022/8/9 14:45
* @description:
*/
public class RoleServiceTest {
@Test
public void getRole(){
AnnotationConfigApplicationContext aa=new AnnotationConfigApplicationContext(BuildRole.class);
RoleService roleService=aa.getBean(RoleService.class);
roleService.printRoleInfo();
}
}
多次实现接口的情况
自动装配的歧义性:Spring建议使用接口编程,每个接口都有一个实现类;但是,在实际开发中一个接口的实现类会有多个,此时自动装配时就有歧义;如果在每个类中都与上文自动注入方式类似;spring将无法识别;在这个时候;可以在原文件的基础上,加上注解@Primary
@Primary:代表首要的,作用是告诉IoC容器,请优先使用该类注入
import com.service.RoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
/**
* @author Una
* @date 2022/8/9 18:58
* @description:
*/
@Component
@Primary
public class RoleServiceImplThree implements RoleService {
@Autowired
private Role role=null;
@Override
public void printRoleInfo() {
System.out.println("第三次实现:"+role.getName());
}
}
Bean的装配方式4----使用@Bean装配
@Bean注解:可以用在方法上,方法返回的对象作为Spring的Bean。不能使用在类上
package com.control;
import com.bean.Role;
import com.impl.RoleServiceImpl;
import com.impl.RoleServiceImplTwo;
import com.service.RoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
/**
* @author Una
* @date 2022/8/9 19:21
* @description:
*/
@Component
public class RoleControl {
@Autowired
@Qualifier(value = "RoleServiceImpl3")
private RoleService roleService=null;
public void getRole(){
roleService.printRoleInfo();
}
@Bean(name = "RoleServiceImpl2")
public RoleService printRole(){
System.out.println("role2");
return new RoleServiceImplTwo();
}
}
测试:
package com.control;
import com.bean.BuildRole;
import com.impl.RoleServiceImplThree;
import com.service.RoleService;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import static org.junit.Assert.*;
/**
* @author Una
* @date 2022/8/9 19:25
* @description:
*/
public class RoleControlTest {
@Test
public void testRole(){
AnnotationConfigApplicationContext aa=new AnnotationConfigApplicationContext(BuildRole.class);
RoleControl rc=(RoleControl) aa.getBean(RoleControl.class);
rc.getRole();
rc.printRole();
}
}
@Component注解和@Bean注解的区别:
(a)@Component注解只能注解在类上,不能注解在方法上。
缺点:在java开发中需要使用第三方的包(jar)时,无法给这些包中的类使用@Component注解,若必须要用只能是新建一个类继承第三方包中的类;然后在自己新建的类上使用@Component注解,这就显的不伦不类。
(b)@Bean注解:不能使用在类上
@Bean(name = "roleServiceImpl1")
'name':是一个字符串的数组,运行配置多个BeanName
'autowire':标志是一个引用的Bean对象,默认为Autowire.NO
'initMethod':自定义初始化方法
'destroyMethod':自定义销毁方法
装配Bean的方式的比较:
1、装配方式:
(1)在XML文件中显式配置
(2)在java的接口和类中实现配置
(3)隐式Bean的发现机制和自动装配(使用注解)
2、装配方式的选择:
(1)基于约定优于配置的原则,优先考虑隐式Bean的发现机制和自动装配原则。
优点:减少开发者的 决定权,简单又灵活
(2)在没有办法使用自动装配时,优先考虑java接口和类中实现配置
(3)若前面两种方法都无法实现时,使用xml方式进行配置