Bean的装配

本文详细介绍了Spring Boot中Bean的四种装配方式:XML文件显式装配,使用@Component注解装配,@Autowired自动装配,以及使用@Bean注解装配。分别阐述了每种方式的使用场景、原则和注意事项,并通过实例展示了装配过程。此外,文章还比较了不同装配方式的特点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是bean的装配

指的是用户将自己开发的Bean装配到Spring Ioc容器中

Bean的装配方式1----在XML文件中显式装配

  1. 简易值的装配
    指的是一般数据类型的装配;比如说Integer、String等;可以参考上一篇博客
  2. 集合装配

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>
  1. 命名空间的装配(一般不使用)

在这里插入图片描述

         a、必须引入对应的命名空间和xml模式文件
         例如:
	   
	      <bean id="role4" class="com.bean.Role" c:_0="1" c:_1="经理" c:_2="部门管理"/>
		  
		b、使用构造器注入 

Bean的装配方式2----使用@Component装配

隐式Bean的发现机制和自动装配原则

组件扫描:通过定义资源的方式,让Spring Ioc容器扫描对应的包从而把Bean装配进来

最基础的扫描

  1. 使用@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 {
}

  1. 在使用时要用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:

  1. 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;
    }
}

  1. 接口文件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);
}

  1. 接口实现类
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()+"]");
    }

}
  1. 扫描文件
    值得注意的是;在扫描文件进行扫描时;需要扫描两个文件或者两个文件所在的包
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扫描
}

  1. 测试文件
    值得注意的是:在测试时必须使用 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为例

实现一个接口的情况

  1. 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;
    }
}
  1. RoleService接口
    在接口中;除了方法;不需要进行别的操作
package com.service;

import com.bean.Role;

/**
 * @author Una
 * @date 2022/8/9 14:22
 * @description:
 */


public interface RoleService {
    public void printRoleInfo();
}

  1. 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()+"]");
    }

}

  1. 扫描文件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扫描
}

  1. 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方式进行配置	 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值