chapter08:@Value赋值
新建chapter08目录:
1,新建Brid.java类
public class Bird {
private String name;
private int age;
private String color;
public Bird() {
}
public Bird(String name, int age, String color) {
this.name = name;
this.age = age;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "Bird{" +
"name='" + name + '\'' +
", age=" + age +
", color='" + color + '\'' +
'}';
}
}
2,新建Chapter08MainConfig.java配置类
@Configuration
public class Chapter08MainConfig {
@Bean
public Bird bird(){
return new Bird();
}
}
3,新建测试用例Chapter08MainTest.java, 从容器获取bean并打印。
public class Chapter08MainTest {
@Test
public void test(){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Chapter08MainConfig.class);
// 从容器中获取所有的bean
String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
Bird bird = (Bird) ctx.getBean("bird");
System.out.println(bird);
ctx.close();
}
}
打印结果:
4,使用@Value赋值如何赋值呢?见下
输出:
5,从配置文件[properties]读取, 新建test.properties
6,在Bird类的color字段添加@Value
7,将test.properties配置文件加载起来。
8,再次运行结果是:
9,test.properties值是加在运行环境变量里
输出:
chapter09:@Autowired自动装配
自动装配:spring利用依赖注入(DI), 完成对IOC容器中的各个组件的依赖关系赋值
1,新建TestController.java TestService.java TestDao; 分别建在指定的包内,可看步骤2
这些所有JAVA 类的对象扫描后都是保存在IOC容器中管理的。
@Repository
public class TestDao {
}
@Service
public class TestService {
@Autowired
private TestDao testDao;
//testDao打印出来(在测试时方便对比)
public void println(){
System.out.println(testDao);
}
}
@Controller
public class TestController {
@Autowired
private TestService service;
}
2,新建配置类Chapter09MainConfig .java,扫描并将以上bean都扫描并加载到容器。
@Configuration
@ComponentScan("com.bruce.chapter09")
public class Chapter09MainConfig {
}
3, 新建Cap9Test.java测试用例,比较TestService拿到testDao与直接从容器中拿到的testDao是否为同一个?
public class Chapter09MainTest {
@Test
public void test(){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Chapter09MainConfig.class);
TestService bean = ctx.getBean(TestService.class);
bean.println();
//直接从容器中获取TestDao和使用@Autowired注解来取比较
TestDao bean1 = ctx.getBean(TestDao.class);
System.out.println(bean1);
ctx.close();
}
}
输出:
小结:
@Autowired表示默认优先按类型去容器中找对应的组件,相当于anno.getBean(TestDao.class)去容器获取id为testDao的bean, 并注入到TestService的bean中。
4,注意事项
4.1,如果容器中找到多个testDao, 会加载哪个testDao呢?
操作步骤:
将TestDao加入flag属性和set, get及toString方法,用来分辨加载了哪个bean。
@Repository
public class TestDao {
//默认是1
private int flag = 1;
public TestDao(){
}
public TestDao(int flag) {
this.flag = flag;
}
public int getFlag() {
return flag;
}
public void setFlag(int flag) {
this.flag = flag;
}
@Override
public String toString() {
return "TestDao{" +
"flag=" + flag +
'}';
}
}
并将在Chapter09MainConfig .java声明@Bean(“testDao”)
@Configuration
@ComponentScan("com.bruce.chapter09")
public class Chapter09MainConfig {
//若TestService获取的testDao是这个bean,应打印出flag为2
@Bean("testDao")
public TestDao testDao(){
return new TestDao(2);
}
}
输出:
说明容器放入的是@Bean标注的testDao,而不是@Repository本身标注的testDao。说明@Bean标注的bean优先级高于@Repository标注的。
4.2, 将在Chapter09MainConfig .java声明@Bean(“testDao2”)
@Configuration
@ComponentScan("com.bruce.chapter09")
public class Chapter09MainConfig {
//若TestService获取的testDao是这个bean,应打印出flag为2
@Bean("testDao2")
public TestDao testDao(){
return new TestDao(2);
}
}
修改测试类:
相当于往容器中注册了bean的id为testDao2的TestDao bean,输出TestDao类型的bean有哪些。
4,3,当有多个同类型的bean的时候,可以根据bean的id来获取不同的bean。
输出:
修改方法中的id:
输出:
4.4,虽然以上定义了private TestDao testDao2, 但还是想加载bean id为testDao(flag=1)的bean,怎么办?此时可以使用@Autowired和@Qualifier结合来指定注入哪一个bean。
输出:
4.5,如果容器中没有任何一个testDao, 会出现什么状况呢?
很明显报错了, 因为@Autowired注解里的属性默认required=true必须找到bean。
那怎么解决呢?
输出:
4.6,@Primary注解指定bean如何加载呢?
以上原注释掉的@Repository和@Bean(“testDao2”) 恢复。
重要:
为了验证@Qualifier与@Primary两注解的加载顺序,测试如下。
修改测试类:
public class Chapter09MainTest {
@Test
public void test(){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Chapter09MainConfig.class);
TestService bean = ctx.getBean(TestService.class);
bean.println();
//直接从容器中获取TestDao和使用@Autowired注解来取比较
TestDao bean1 = ctx.getBean(TestDao.class);
System.out.println("getbean........testDao....." + bean1);
String[] beanNamesForType = ctx.getBeanNamesForType(TestDao.class);
for (String s : beanNamesForType) {
System.out.println(s);
}
ctx.close();
}
}
输出:
TestService…testDao…TestDao{flag=1}:TestService打印的结果:使用了@Qualifier,表示直接到容器中找寻testDao的bean,flag= 1。
getbean…testDao…TestDao{flag=2}:直接使用ctx.getBean(TestDao.class),获取到的是@Primary注解声明的bean,flag = 2。
4,7,此时只能说明一点: @Qualifier是根据bean id指定获取testDao, 不受@Primary影响.
那么@Primary的功能在哪呢?继续测试…
输出:
很明显都是注入@Primary指定的testDao,通过@Primary标记的bean,它的bean默认被首选使用。
注意:
如果注销掉@Primary,再通过ctx.getBean(TestDao.class)获取会报错,因为存在两个类型为TestDao的bean,没有默认选择哪个,就会报错。
4.8,除了@Autowired, 是不是还用过@Resource(JSR250) 和@Inject(JSR330) 。
将Qualifier和Autowired注释掉(注意: 此时@Primary 还没注释…)
测试结果:
效果也是一样的, 但它不先优先装配@Primary的bean。
小结:
@Resource和Autowired的区别如下:
@Resource和Autowired一样可以装配bean
@Resource缺点: 不能支持@Primary功能
不能支持@Autowired(required = false)的功能
4.9, @Inject自动装配的使用
注:@Inject与@Autowired的区别如下:
@Inject和Autowired一样可以装配bean, 并支持@Primary功能, 可用于非spring框架.
@Inject缺点: 但不能支持@Autowired(required = false)的功能,需要引入第三方包javax.inject
操作步骤:
1,pom.xml导入javax.inject包
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
2,使用@Inject注解
输出:
结论:@Inject不支持required=false, 但支持primary。
总结:
Autowired属于spring的, 不能脱离spring, @Resource和@Inject都是JAVA规范
推荐大家使用@Autowired。