spring中给bean的属性赋值

  • xml文件properties标签设置

    <bean id="student" class="com.enjoy.study.cap10.Student" >
    <property name="id" value="18"/>
    <property name="name" value="wxf"/>
    </bean>
  • 注解
    • @Autowired
    • @Value
    • @Resource  JSR250
    • @Inject    JSR330

本章博客重点介绍注解赋值的使用


@Autowired

自动装配:Spring利用依赖注入完成对IOC容器中各个组件的依赖关系赋值

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})

可以在构造方法、方法、参数、属性以及注解上使用,最常用的就是在属性上使用

不管使在什么地方使用,都是从IOC容器中获取bean

基本使用

@Configuration
@ComponentScan("com.enjoy.study.cap11")
public class CapMainConfig { }

@Repository
public class TestDao {
public void test(){
System.out.println("---------TestDao test()--------");
}
}
@Service
public class TestService {
@Autowired
private TestDao testDao; public void test() { System.out.println("---------TestService test()--------"+testDao);
} public TestDao getTestDao() {
return testDao;
} public void setTestDao(TestDao testDao) {
this.testDao = testDao;
}
}

测试
public class TestCap {
@Test
public void testMethod(){
ApplicationContext context = new AnnotationConfigApplicationContext(CapMainConfig.class);
TestDao testDao = (TestDao) context.getBean("testDao"); TestService service = (TestService) context.getBean("testService");
TestDao testDao1 = service.getTestDao(); System.out.println(testDao==testDao1);
}
}

结果
true

结论:

  • @Autowired注解先按照类型去IOC容器中找到相应组件,再将id为testDao的bean取出并注入TestService的testDao属性中
  • 如果没有找到该id对应的bean,就将相同类型的bean注入,不会报错

优先级

当容器中有多个相同类型的bean,使用@Autowired注解注入哪一个?

@Configuration
@ComponentScan("com.enjoy.study.cap11")
public class CapMainConfig { @Bean("testDao2")
public TestDao testDao(){
TestDao testDao = new TestDao();
testDao.setFlag(2);
return testDao;
}
}

@Repository
public class TestDao {
private int flag = 1; public int getFlag() {
return flag;
} public void setFlag(int flag) {
this.flag = flag;
} @Override
public String toString() {
return "TestDao{" +
"flag=" + flag +
'}';
}
}
@Service
public class TestService {
@Autowired
private TestDao testDao2; public TestDao getTestDao() {
return testDao2;
} public void setTestDao(TestDao testDao) {
this.testDao2 = testDao;
}
}

测试类
public class TestCap {
@Test
public void testMethod(){
ApplicationContext context = new AnnotationConfigApplicationContext(CapMainConfig.class); TestService service = context.getBean(TestService.class);
TestDao testDao1 = service.getTestDao(); System.out.println(testDao1);
}
}

结果
TestDao{flag=2}

结论:

  TestService中注入的是testDao2;另外,如果TestService中定义private TestDao testDao;那么结果是TestDao{flag=1},也就是TestService中注入的是testDao

指定注入哪个bean

如果TestService中定义private TestDao testDao;还是想要注入testDao,那么可以使用@Qualifier+@Autowired

@Service
public class TestService {
@Qualifier("testDao")
@Autowired

private TestDao testDao2; public TestDao getTestDao() {
return testDao2;
} public void setTestDao(TestDao testDao) {
this.testDao2 = testDao;
}
}

结果
TestDao{flag=1}

required属性

当容器中不存在该类型的bean时:

将配置类中的@Bean和TestDao类的@Repository注释掉

@Configuration
@ComponentScan("com.enjoy.study.cap11")
public class CapMainConfig { //@Bean("testDao")
public TestDao testDao(){
TestDao testDao = new TestDao();
testDao.setFlag(2);
return testDao;
}
}

//@Repository
public class TestDao {
private int flag = 1; public int getFlag() {
return flag;
} public void setFlag(int flag) {
this.flag = flag;
} @Override
public String toString() {
return "TestDao{" +
"flag=" + flag +
'}';
}
}
@Service
public class TestService {
@Autowired
private TestDao testDao2; public TestDao getTestDao() {
return testDao2;
} public void setTestDao(TestDao testDao) {
this.testDao2 = testDao;
}
}

public class TestCap {
@Test
public void testMethod(){
ApplicationContext context = new AnnotationConfigApplicationContext(CapMainConfig.class); TestService service = context.getBean(TestService.class);
TestDao testDao1 = service.getTestDao(); System.out.println(testDao1);
}
}

结果
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'com.enjoy.study.cap11.dao.TestDao' available:
expected at least 1 bean which qualifies as autowire candidate.
Dependency annotations:
{@org.springframework.beans.factory.annotation.Autowired(required=true)}

结论:

  启动容器,两个TestDao类型的bean都不会被加载,并且提示异常报错;原因是@Autowired注解的required属性默认为true,即要求容器中必须存在bean,否则抛出异常

使用@Autowired(required=false)即可解决

@Service
public class TestService {
@Autowired(required = false)
private TestDao testDao2; public TestDao getTestDao() {
return testDao2;
} public void setTestDao(TestDao testDao) {
this.testDao2 = testDao;
}
}

结果
null

结论:

  因为容器中没有TestDao类型的bean,所以打印结果为null

验证@Qualifier和@Primary加载顺序

@Primary的作用是使得该bean默认优先被使用

应用场景:多个类都需要注入一个bean时,如果每个类都使用@Qualifier指定注入相同的bean会导致代码冗余,这时可以使用@Primary直接在该bean上作用即可

@Configuration
@ComponentScan("com.enjoy.study.cap11")
public class CapMainConfig { @Primary
@Bean("testDao2")
public TestDao testDao(){
TestDao testDao = new TestDao();
testDao.setFlag(2);
return testDao;
}
}

@Repository
public class TestDao {
private int flag = 1; public int getFlag() {
return flag;
} public void setFlag(int flag) {
this.flag = flag;
} @Override
public String toString() {
return "TestDao{" +
"flag=" + flag +
'}';
}
}
@Service
public class TestService {
@Qualifier("testDao")
@Autowired(required = false)

private TestDao testDao2; public TestDao getTestDao() {
return testDao2;
} public void setTestDao(TestDao testDao) {
this.testDao2 = testDao;
}
}

public class TestCap {
@Test
public void testMethod(){
ApplicationContext context = new AnnotationConfigApplicationContext(CapMainConfig.class);
TestDao testDao = context.getBean(TestDao.class);
System.out.println("context.getBean(TestDao.class) = " + testDao); TestService service = context.getBean(TestService.class);
TestDao testDao1 = service.getTestDao();
System.out.println("service.getTestDao() = " + testDao1);
}
}

结果
context.getBean(TestDao.class) = TestDao{flag=2}
service.getTestDao() = TestDao{flag=1}

结论1:

  • TestService中注入的是testDao,直接从容器中获取时取到的是testDao2
  • 说明@Qualifier是根据bean的id获取的bean,不受@Primary影响

修改TestService类

@Service
public class TestService {
// @Qualifier("testDao")
@Autowired(required = false)
private TestDao testDao; public TestDao getTestDao() {
return testDao;
} public void setTestDao(TestDao testDao) {
this.testDao = testDao;
}
}
结果
context.getBean(TestDao.class) = TestDao{flag=2}
service.getTestDao() = TestDao{flag=2}

结论2:

  • 注入的都是@Primary指定的testDao2
  • 通过@Primary标记的bean,默认首先被使用  

@Value

@Configuration
public class CapMainConfig {
@Bean
public Student student(){
return new Student();
}
}

public class TestCap {
@Test
public void testMethod(){
ApplicationContext context = new AnnotationConfigApplicationContext(CapMainConfig.class);
Student student = (Student) context.getBean("student");
System.out.println("student = " + student);
}
}

字符形式@Value("")

public class Student {
@Value("12")
private Integer id;
@Value("wxf")
private String name; @Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
} 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;
}
}

结果

student = Student{id=12, name='wxf'}

@Value("#{}")

@Value("#{}") 表示SpEl表达式,通常用来获取bean的属性,或者调用bean的某个方法

容器中bean类:

public class TestBean {
@Value("qf")
private String name;
@Value("12")
private Integer id; 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 class Student {
@Autowired
private TestBean testBean; //表达式,或者字符形式#{1}
@Value("#{12-1}")
private String sex; //bean属性
@Value("#{testBean.id}")
private Integer id; //bean方法
@Value("#{testBean.getName()}")
private String name; public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
} 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;
} @Override
public String toString() {
return "Student{" +
"sex='" + sex + '\'' +
", id=" + id +
", name='" + name + '\'' +
'}';
}
}
配置类
@Configuration
public class CapMainConfig {
@Bean
public TestBean testBean(){
return new TestBean();
}
@Bean
public Student student(){
return new Student();
}
}

测试类
public class TestCap {
@Test
public void testMethod(){
ApplicationContext context = new AnnotationConfigApplicationContext(CapMainConfig.class);
Student student = (Student) context.getBean("student");
System.out.println("student = " + student);
}
}

结果
student = Student{sex='11', id=12, name='qf'}

@Value("${}")

通过@Value("${}") 可以获取对应属性文件中定义的属性值

想要使用${}方式获取值

  首先通过@PropertySource注解将properties配置文件中的值存储到Spring的 Environment中,Environment接口提供方法去读取配置文件中的值,参数是properties文件中定义的key值

@Configuration
@PropertySource(value={"classpath:test.properties","classpath:test2.properties"})
public class MainConfig {
@Bean
public Person person(){
return new Person();
}
}

测试

配置文件
test.properties文件
TestStr=12345 test2.properties文件
TestStr1=123456789

bean类
public class Person {
@Value("${TestStr}")
private Integer id; public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
}
}

测试
public class TestCap {
@Test
public void testM(){
ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
Person person = context.getBean(Person.class);
System.out.println("person.getId() = " + person.getId());
}
}

结果
person.getId() = 12345 

@Resource

基本使用

@Configuration
@ComponentScan("com.enjoy.study.cap11")
public class CapMainConfig {
@Primary
@Bean("testDao2")
public TestDao testDao(){
TestDao testDao = new TestDao();
testDao.setFlag(2);
return testDao;
}
}

@Repository
public class TestDao {
private int flag = 1; public int getFlag() {
return flag;
} public void setFlag(int flag) {
this.flag = flag;
} @Override
public String toString() {
return "TestDao{" +
"flag=" + flag +
'}';
}
}
@Service
public class TestService {
@Resource
private TestDao testDao; public TestDao getTestDao() {
return testDao;
} public void setTestDao(TestDao testDao) {
this.testDao = testDao;
}
}

public class TestCap {
@Test
public void testMethod(){
ApplicationContext context = new AnnotationConfigApplicationContext(CapMainConfig.class);
TestDao testDao = context.getBean(TestDao.class);
System.out.println("context.getBean(TestDao.class) = " + testDao); TestService service = context.getBean(TestService.class);
TestDao testDao1 = service.getTestDao();
System.out.println("service.getTestDao() = " + testDao1);
}
}

结果
context.getBean(TestDao.class) = TestDao{flag=2}
service.getTestDao() = TestDao{flag=1}

结论:

  • @Primary对@Resource并不生效
  • @Resource和@Autowired一样可以装配bean

name属性

可以指定注入哪个bean

@Service
public class TestService {
@Resource(name = "testDao2")
private TestDao testDao; public TestDao getTestDao() {
return testDao;
} public void setTestDao(TestDao testDao) {
this.testDao = testDao;
}
}

结果
context.getBean(TestDao.class) = TestDao{flag=2}
service.getTestDao() = TestDao{flag=2}

bean为null的情况

将TestDao上的@Repository和配置类中的@Bean都注释掉,再测试会抛出异常

org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'testDao2' available

所以@Resource并不支持类似@Autowired(required=false)的功能


@Inject

基本使用

需要导入javax.inject的包

<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>

测试

@Configuration
@ComponentScan("com.enjoy.study.cap11")
public class CapMainConfig {
@Primary
@Bean("testDao2")

public TestDao testDao(){
TestDao testDao = new TestDao();
testDao.setFlag(2);
return testDao;
}
}
@Repository
public class TestDao {
private int flag = 1; public int getFlag() {
return flag;
} public void setFlag(int flag) {
this.flag = flag;
} @Override
public String toString() {
return "TestDao{" +
"flag=" + flag +
'}';
}
}
@Service
public class TestService {
@Inject
private TestDao testDao; public TestDao getTestDao() {
return testDao;
} public void setTestDao(TestDao testDao) {
this.testDao = testDao;
}
}
public class TestCap {
@Test
public void testMethod(){
ApplicationContext context = new AnnotationConfigApplicationContext(CapMainConfig.class);
TestDao testDao = context.getBean(TestDao.class);
System.out.println("context.getBean(TestDao.class) = " + testDao); TestService service = context.getBean(TestService.class);
TestDao testDao1 = service.getTestDao();
System.out.println("service.getTestDao() = " + testDao1);
}
}
结果
context.getBean(TestDao.class) = TestDao{flag=2}
service.getTestDao() = TestDao{flag=2}

结论:

@Inject支持@Primary

bean为null的情况

将TestDao上的@Repository和配置类中的@Bean都注释掉,再测试会抛出异常

org.springframework.beans.factory.NoSuchBeanDefinitionException

@Inject并不支持类似@Autowired(required=false)的功能

spring(四):spring中给bean的属性赋值的更多相关文章

  1. Spring(四)--bean的属性赋值

    bean的属性赋值 1.需要的实体类 2.需要的配置文件 <?xml version="1.0" encoding="UTF-8"?> <be ...

  2. [原创]java WEB学习笔记98:Spring学习---Spring Bean配置及相关细节:如何在配置bean,Spring容器(BeanFactory,ApplicationContext),如何获取bean,属性赋值(属性注入,构造器注入),配置bean细节(字面值,包含特殊字符,引用bean,null值,集合属性list map propert),util 和p 命名空间

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  3. 【Spring注解驱动开发】如何使用@Value注解为bean的属性赋值,我们一起吊打面试官!

    写在前面 在之前的文章中,我们探讨了如何向Spring的IOC容器中注册bean组件,讲解了有关bean组件的生命周期的知识.今天,我们就来一起聊聊@Value注解的用法. 项目工程源码已经提交到Gi ...

  4. spring 在容器中一个bean依赖另一个bean 需要通过ref方式注入进去 通过构造器 或property

    spring  在容器中一个bean依赖另一个bean 需要通过ref方式注入进去 通过构造器 或property

  5. 【spring源码系列】之【Bean的属性赋值】

    每次进入源码的世界,就像完成一场奇妙的旅行! 1. 属性赋值概述 上一篇讲述了bean实例化中的创建实例过程,实例化后就需要对类中的属性进行依赖注入操作,本篇将重点分析属性赋值相关流程.其中属性赋值, ...

  6. spring中的bean的属性scope

    spring中bean的scope属性,有如下5种类型: singleton 表示在spring容器中的单例,通过spring容器获得该bean时总是返回唯一的实例 prototype表示每次获得be ...

  7. Spring实战(四)Spring高级装配中的bean profile

    profile的原意为轮廓.剖面等,软件开发中可以译为“配置”. 在3.1版本中,Spring引入了bean profile的功能.要使用profile,首先要将所有不同的bean定义整理到一个或多个 ...

  8. Spring基础——在Spring Config 文件中配置 Bean

    一.基于 XML 的 Bean 的配置——通过全类名(反射) <bean <!-- id: bean 的名称在IOC容器内必须是唯一的若没有指定,则自动的将全限定类名作为 改 bean 的 ...

  9. Spring笔记04(DI(给属性赋值),自动装配(autowire))

    给不同数据类型注入值: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="h ...

随机推荐

  1. [Luogu2600]合并神犇(dp,贪心)

    [Luogu2600]合并神犇 题目背景 loidc来到了NOI的赛场上,他在那里看到了好多神犇. 题目描述 神犇们现在正排成一排在刷题.每个神犇都有一个能力值p[i].loidc认为坐在附近的金牌爷 ...

  2. php7 mysqli连接mysql的几种方式

    一.过程是方法 function connect(){ static $conn; if(!$conn){ $conn = mysqli_connect(DB_HOST,DB_USER,DB_PWD) ...

  3. 多线程、同步实现方法及Error和Exception的区别与联系

    多线程.同步实现方法? 实现线程有两种方法: 继承Thread类 实现Runnable接口 实现同步也有两种方法 一种是用同步方法:同步方法就是在方法返回类型后面加上synchronized, 比如: ...

  4. django之csrf_exempt解决跨域请求的问题

    一: from django.views.decorators.csrf import csrf_exempt # 获取微信返回的code信息 @csrf_exempt def wechat_auth ...

  5. django之静态文件的设置

    一:静态文件 Django中提供了一种解析的方式配置静态文件路径.静态文件可以放在项目根目录下,也可以放在应用的目录下,由于有些静态文件在项目中是通用的,所以推荐放在项目的根目录下,方便管理. 为了提 ...

  6. 对webpack的初步研究8

    模块 编辑文档 在模块化编程中,开发人员将程序分解为称为模块的离散功能块. 每个模块的表面积小于完整程序,使验证,调试和测试变得微不足道.编写良好的模块提供了可靠的抽象和封装边界,因此每个模块在整个应 ...

  7. 写一下SPFA和迪杰斯特拉的模版。。。第一次写博客,有错请提出哦!

    SPFA的模版 #include<bits/stdc++.h> using namespace std; queue <int> q; typedef pair <int ...

  8. [UOJ211][UER #6]逃跑

    题意:从原点出发,走\(n\)次,每次往四个方向中随机一个走,走每个方向有个概率,求所有方案走到过的点数的方差. 题解:orz kczno1 \(E*all=\sum (a_i-avg)^2*all= ...

  9. Xenu Link Sleuth 简单好用的链接测试工具

    XenuLink Sleuth 名词介绍 “Xenu链接检测侦探”是被广泛使用的死链接检测工具.可以检测到网页中的普通链接.图片.框架.插件.背景.样式表.脚本和java程序中的链接. 那么神马时候出 ...

  10. python_012

    一.内置函数 1.sorted()排序函数 a:语法sorted(Iterable,key = None,reverse = False) Iterable:可迭代对象;key:排序规则(函数) ls ...