前面几个章节介绍了bean的定义,在一个完整的应用中,各个bean并不是相互独立的,而是一起工作的,在spring中,通过注入来把这些独立的bean串起来。
基于构造方法的注入
XML
在xml配置文件中,是通过constructor-arg
标签来实现注入。
xml配置如下:
person代码:
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试代码
@Test
public void test() {
ApplicationContext app = new ClassPathXmlApplicationContext("di.xml");
Person person1 = app.getBean("byType",Person.class);
Person person2 = app.getBean("byName",Person.class);
Person person3 = app.getBean("byIndex",Person.class);
System.out.println(person1);
System.out.println(person2);
System.out.println(person3);
}
运行结果如下:
第一个是通过类型注入,第二个是通过名称注入,第三个是通过索引位置注入。
注解
在注解中,常用的注解是@Autowired。
MyService,MyController
@Service
public class MyService {
}
@Controller
public class MyController {
MyService myService;
public MyController(@Autowired MyService myService) {
this.myService = myService;
}
}
MyConfig
@Configuration
@ComponentScan(value="com.learn.annotation2")
public class MyConfig {
}
测试代码:
@Test
public void test(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyConfig.class);
MyController myController=app.getBean("myController",MyController.class);
System.out.println(myController.myService);
System.out.println(app.getBean("myService"));
}
运行结果如下:
两次打印的地址是一样的,说明已经成功注入到myController中。如果想实现上面XML那种基本类型的注入,可以用@Bean注解,通过return new一个对象来实现。
基于setter方法的注入
XML
di.xml配置如下:
person2代码如下:
public class Person2 {
private String name;
private int age;
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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试代码:
@Test
public void test2() {
ApplicationContext app = new ClassPathXmlApplicationContext("di.xml");
Person2 person2 = app.getBean("person2",Person2.class);
System.out.println(person2);
}
运行结果如下:
不同于构造器注入,setter只能通过名称注入。
ref
上面注解可以直接注入容器的对象,在XML配置中,也可以使用ref来注入。
di2.xml配置如下:
Persons代码如下:
public class Persons {
Person person1;
Person person2;
public Persons(Person person1) {
this.person1 = person1;
}
public Person getPerson2() {
return person2;
}
public void setPerson2(Person person2) {
this.person2 = person2;
}
@Override
public String toString() {
return "Persons{" +
"person1=" + person1 +
", person2=" + person2 +
'}';
}
}
运行结果如下:
ref后面的值,是bean的标识符。
p-namespace和c-namespace
dim5.xml
Person3
public class Person3 {
private String name;
private int age;
private String tel;
public Person3(String tel) {
this.tel = tel;
}
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;
}
@Override
public String toString() {
return "Person3{" +
"name='" + name + '\'' +
", age=" + age +
", tel='" + tel + '\'' +
'}';
}
}
测试代码:
@Test
public void test6() {
ApplicationContext app = new ClassPathXmlApplicationContext("di5.xml");
Person3 person3 = app.getBean("person3", Person3.class);
System.out.println(person3);
}
运行结果
这种写法,要引入xmlns:p和xmlns:c。p相对于property,c相对于constructor-arg。
注解
在注解中,方法名也不一定要setXXX,而且@Autowired支持直接在成员上面使用。
MyController
@Controller
public class MyController {
@Autowired
MyService myService;
MyDao myDao;
@Autowired
public void myDao(MyDao myDao) {
this.myDao = myDao;
}
}
测试代码:
@Test
public void test(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyConfig.class);
MyController myController=app.getBean("myController",MyController.class);
System.out.println(myController.myService);
System.out.println(myController.myDao);
System.out.println(app.getBean("myService"));
System.out.println(app.getBean("myDao"));
}
运行结果如下:
两次打印的地址是一样的,说明已经成功注入到myController中。
构造器注入和setter注入
在系统中,我们既可以用构造器注入,也可以用setter注入,甚至可以两种一起用,都可以达到我们想要的效果。
构造器注入:强依赖,大量的构造函数参数不是很优雅,无法解决循环依赖的问题,会抛出BeanCurrentlyInCreationException异常。
setter注入:可选依赖,可以重新注入。
内部类注入
di3.xml配置信息:
Outer类
public class Outer {
private Inner inner;
public Inner getInner() {
return inner;
}
public void setInner(Inner inner) {
this.inner = inner;
}
static class Inner{
private String name;
private int age;
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;
}
@Override
public String toString() {
return "Inner{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
@Override
public String toString() {
return "Outer{" +
"inner=" + inner +
'}';
}
}
测试代码
@Test
public void test4() {
ApplicationContext app = new ClassPathXmlApplicationContext("di3.xml");
Outer outer = app.getBean("outer", Outer.class);
System.out.println(outer);
}
运行结果:
内部类的bean定义,不需要id和name。因为是内部类,所以即便设置了,容器也会忽略。
集合
di4.xml配置如下:
aaa
bbb
ccc
aaa
bbb
ccc
李四
20
ddd
eee
fff
ddd
eee
fff
男
13800138000
AbstractCollect和Collect
public abstract class AbstractCollect {
List list;
Set set;
Map map;
Properties properties;
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
public Set getSet() {
return set;
}
public void setSet(Set set) {
this.set = set;
}
public Map getMap() {
return map;
}
public void setMap(Map map) {
this.map = map;
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
return "AbstractCollect{" +
"list=" + list +
", set=" + set +
", map=" + map +
", properties=" + properties +
'}';
}
}
public class Collect extends AbstractCollect{
}
测试类:
@Test
public void test5() {
ApplicationContext app = new ClassPathXmlApplicationContext("di4.xml");
Collect collect = app.getBean("collect", Collect.class);
System.out.println(collect);
}
运行结果如下:
merge为true且设置了parent的时候,可以继承父类的信息。merge的时候,必须是同一类型的对象。
其他
空值的处理
如果是空字符串,以下是等同的。
exampleBean.setEmail("");
如果是null,以下是等同的。
exampleBean.setEmail(null);
depends-on和@DependsOn
当A对象包含B对象的时候,A对象初始化时,B对象必须初始完成。如果A对象没有包含B对象,也需要B对象初始化完成后,才初始化A,那可以用depends-on。
di6.xml
One和Two
public class One {
public One(){
System.out.println("one init");
}
}
public class Two {
public Two(){
System.out.println("two init");
}
}
测试代码
@Test
public void test7() {
new ClassPathXmlApplicationContext("di6.xml");
}
当有depends-on="two"的时候,运行结果如下:
否则运行结果如下
说明depends-on生效了。@DependsOn这边就不做例子了。