前面几个章节介绍了bean的定义,在一个完整的应用中,各个bean并不是相互独立的,而是一起工作的,在spring中,通过注入来把这些独立的bean串起来。
在xml配置文件中,是通过 constructor-arg
标签来实现注入。
xml配置如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="byType" class="com.learn.di.Person"> <constructor-arg type="java.lang.String" value="张三"/> <constructor-arg type="int" value="18"/> </bean> <bean id="byName" class="com.learn.di.Person"> <constructor-arg name="name" value="李四"/> <constructor-arg name="age" value="19"/> </bean> <bean id="byIndex" class="com.learn.di.Person"> <constructor-arg index="0" value="王五"/> <constructor-arg index="1" value="20"/> </bean> </beans>
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一个对象来实现。
di.xml配置如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="person2" class="com.learn.di.Person2"> <property name="name" value="赵六"/> <property name="age" value="21"/> </bean> </beans>
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只能通过名称注入。
上面注解可以直接注入容器的对象,在XML配置中,也可以使用ref来注入。
di2.xml配置如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <import resource="di.xml"/> <bean id="persons" class="com.learn.di.Persons"> <constructor-arg name="person1" ref="byName"/> <property name="person2" ref="byType"/> </bean> </beans>
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的标识符。
dim5.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="person3" class="com.learn.di.Person3" c:tel="13800138000" p:name="张三" p:age="18"/> </beans>
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注入,甚至可以两种一起用,都可以达到我们想要的效果。
构造器注入:强依赖,大量的构造函数参数不是很优雅,无法解决循环依赖的问题,会抛出BeanCurrentlyInCreationException异常。
setter注入:可选依赖,可以重新注入。
di3.xml配置信息:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="outer" class="com.learn.di.Outer"> <property name="inner"> <bean class="com.learn.di.Outer.Inner"> <property name="name" value="张三"/> <property name="age" value="18"/> </bean> </property> </bean> </beans>
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。因为是内部类,所以即便设置了,容器也会忽略。
如果是空字符串,以下是等同的。
<bean class="ExampleBean"> <property name="email" value=""/> </bean>
exampleBean.setEmail("");
如果是null,以下是等同的。
<bean class="ExampleBean"> <property name="email"> <null/> </property> </bean>
exampleBean.setEmail(null);
当A对象包含B对象的时候,A对象初始化时,B对象必须初始完成。如果A对象没有包含B对象,也需要B对象初始化完成后,才初始化A,那可以用depends-on。
di6.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="one" class="com.learn.di.One" depends-on="two"/> <bean id="two" class="com.learn.di.Two"/> </beans>
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这边就不做例子了。