spring自动装配

 

自动装配,到底是什么,这对于新手来说,比如说我刚入行的时候,总觉得很神秘,百思不得其解。下面二万给大家来剖析一下

一个对象A,对另外对象的引用B,在传统方式上,需要在A中new一个对象B,或者通过构造函数中传入一个new出来的B。

自动装配就是可以简单的理解通过@Autowired,在A中声明一下B就可以直接使用B并不需要new一个B对象。

很多新手也会疑问,我new不new不就一行代码的问题吗,通过自动装配可以达到对象的使用和创建解耦,将对象B的管理交给ioc容器。这里可以自行百度一下。

下面,我们来探究@Autowired的神秘面纱吧

二话不说,先新建配置类,并且进行注解扫描包

@Configuration
@ComponentScan("com.erwan.cap9")
public class Cap9MainConfig {
	@Bean("testDao2")
	public TestDao testDao2() {
		TestDao testDao = new TestDao();
		testDao.setNum(2);
		return testDao;
	}
	@Bean
	public TestDao testDao() {
		TestDao testDao = new TestDao();
		return testDao;
	}
}

再建一个TestDao


public class TestDao {
	public Integer num = 1;

	public TestDao() {

	}

	public Integer getNum() {
		return num;
	}

	public void setNum(final Integer num) {
		this.num = num;
	}

	@Override
	public String toString() {
		return "OrderDao [num=" + num + "]";
	}
}

新建两个服务类TestService1,TestService2,都持有TestDao的引用

@Service
public class TestService {
	@Autowired
	private TestDao testDao;

	public void println() {
		System.out.println("TestService ......." + testDao);
	}
}


@Service
public class TestService2 {
	@Autowired
	private TestDao testDao2;//如果ioc容器中没有testDao2,则会注入testDao

	public void println() {
		System.out.println("TestService2 ......." + testDao2);
	}
}

新建测试类

@Test
public void cap9() {
	AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Cap9MainConfig.class);
	TestService testService1 = context.getBean(TestService.class);
	TestService2 testSerice2 = context.getBean(TestService2.class);

	testService1.println();
	testSerice2.println();
}

OrderDao [num=1]
OrderDao [num=2]
TestService .......OrderDao [num=1]
TestService2 .......OrderDao [num=2]

通过测试结果可以看到,当注册的名称为testDao2时,TestService2中持有的实例是配置类里面beanName为testDao2的实例

接下来 我们在TestDao里面加一个注解,@Primary

@Repository
@Primary
public class TestDao {
	public Integer num = 1;

	public TestDao() {

	}

	public Integer getNum() {
		return num;
	}

	public void setNum(final Integer num) {
		this.num = num;
	}

	@Override
	public String toString() {
		return "OrderDao [num=" + num + "]";
	}
}

测试结果如下

OrderDao [num=1]
OrderDao [num=2]
TestService .......OrderDao [num=1]
TestService2 .......OrderDao [num=1]

从结果上面来看,只要在TestDao类上加了@Primary这个注解,就是以这个为准。

接下来我们在TestService1中加入    @Qualifier("testDao2")

@Service
public class TestService {
	@Autowired
	@Qualifier("testDao2")
	private TestDao testDao;

	public void println() {
		System.out.println("TestService ......." + testDao);
	}
}

执行测试类 


TestService .......OrderDao [num=2]
TestService .......OrderDao [num=1]

从结果分析,当你指定了哪个bean实例注入,它就以该实例为准,@Primary并不生效。

所以总结一下,根据名称注入<@Primary<@Qualifier ,其中需要注意一点的是根据名称(也就是TestService2中的TestDao testDao2)注入testDao2,如果找不到testDao2,则会自动注入testDao

接下来我们继续看@Autowired的required属性

在配置类里面注释掉testDao2的定义,

@Configuration
@ComponentScan("com.erwan.cap9")
public class Cap9MainConfig {
	// @Bean("testDao2")
	// public TestDao testDao2() {
	// TestDao testDao = new TestDao();
	// testDao.setNum(2);
	// return testDao;
	// }
	@Bean
	public TestDao testDao() {
		TestDao testDao = new TestDao();
		return testDao;
	}
}

然后执行测试类,会报错。因为@Autowired默认required是true,如果在ioc容器里面找bean(testDao2)找不到会报错

我们把TestService里面的@Autowired(required=false)

@Service
public class TestService {
	@Autowired(required = false)
	@Qualifier("testDao2")
	private TestDao testDao;

	public void println() {
		System.out.println("TestService ......." + testDao);
	}
}

测试结果如下

TestService .......null
TestService .......OrderDao [num=1]

所以Autowired中的required=false的作用不言而喻,就是为了在ioc找不到依赖的bean(testDao2)时,会注入一个空,并不会报错.

 

接下来我们看看@Autowired可以使用的地方,在@Autowired的地方按F3,可以看到如下

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {

@Target中指定的包括构造函数,方法,参数,字段等

这里我们做个简单的实验

 

新建配置类,把水果类都扫描到ioc容器中

@ComponentScan("com.erwan.cap10.bean")
public class Cap10MainConfig {

}

新建下面水果类  fruit,banana,apple,pears ,并且在类上都加入@Component

@Component
public class Fruit {
	private Banana banana;
	private Apple apple;
	private Pear pear;
	private Plum plum;

	@Override
	public String toString() {
		return "Fruit [banana=" + banana + ", apple=" + apple + ", pear=" + pear + ", plum=" + plum + "]";
	}
}

@Component
public class Apple {

}
@Component
public class Banana {

}
@Component
public class Pear {

}

新建一个测试类

	@Test
	public void cap10() {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Cap10MainConfig.class);
		Pear pear = context.getBean(Pear.class);
		Fruit fruit = context.getBean(Fruit.class);
		System.out.println(pear);
		System.out.println(fruit);
	}

测试结果如下
com.erwan.cap10.bean.Pear@cc43f62
Fruit [banana=null, apple=null, pear=null]

从结果上来看,ioc确实把单例的bean在启动的时候就创建了,但是在Fruit中的所依赖的属性都是空的值。

现在我们通过@Autowired来看看,修改Fruit类

@Component
public class Fruit {
	@Autowired
	private Banana banana;
	private Apple apple;
	private Pear pear;

	Fruit() {

	}

	@Autowired
	Fruit(final Apple apple) {
		this.apple = apple;
	}

	@Autowired
	public void setPear(final Pear pear) {
		this.pear = pear;
	}

	@Override
	public String toString() {
		return "Fruit [banana=" + banana + ", apple=" + apple + ", pear=" + pear + "]";
	}
}

启动测试类,结果如下

com.erwan.cap10.bean.Pear@3e08ff24
Fruit [banana=com.erwan.cap10.bean.Banana@4d1c005e, apple=com.erwan.cap10.bean.Apple@8462f31, pear=com.erwan.cap10.bean.Pear@3e08ff24]

最后我们来看看 和Autowired相类似的注解

@Autowired可以自动注入,@Resource(JSR250)  和@Inject(JSR330) 这两个注解也是可行的

这里就不演示了,说一下这三者的区别

注:@Resource与@Autowired的区别如下:

@Resource和Autowired一样可以装配bean

@Resource缺点: 不能支持@Primary功能,不能支持@Autowired(required = false)的功能

@Resource(name="testDao2") 可以通过名称来注入指定bean

@Qualifier("testDao2")对@Resource并不起作用

注:@Inject与@Autowired的区别如下:

@Inject和Autowired一样可以装配bean, 并支持@Primary功能, 可用于非spring框架.

@Inject缺点: 但不能支持@Autowired(required = false)的功能,需要引入第三方包javax.inject

 

 

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值