Spring注入方式及实例
SpringMVC搭建一个Web项目:链接跳转点我
1.接口注入(不推荐)
从注入方式的使用上来说,接口注入是现在不提倡的一种方式,基本处于“退役状态”。因为它强制被注入对象实现不必要的接口,带有侵入性。而构造方法注入和setter方法注入则不需要如此。
2.构造方法注入
将依赖关系作为构造函数参数传入的做法称为构造器注入(Constructor Injection)。这种注入方式的优点就是,对象在构造完成之后,即已进入就绪状态,可以马上使用。缺点就是,当依赖对象比较多的时候,构造方法的参数列表会比较长。而通过反射构造对象的时候,对相同类型的参数的处理会比较困难,维护和使用上也比较麻烦。而且在Java中,构造方法无法被继承,无法设置默认值。对于非必须的依赖处理,可能需要引入多个构造方法,而参数数量的变动可能造成维护上的不便。
例
applicationContext.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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<!-- 构造器注入 -->
<bean id="userConstructor" class="cn.com.demo.User">
<constructor-arg value="1"/>
<constructor-arg value="user1"/>
</bean>
</beans>
在进行构造器注入的时候,也可以用index来定义构造器中参数的顺序。
<bean id="userConstructor" class="cn.com.demo.User">
<constructor-arg value="1" index="0"/>
<constructor-arg value="user1" index="1"/>
</bean>
也可以通过属性的类型进行定义。
<bean id="userConstructor" class="cn.com.demo.User">
<constructor-arg value="1" type="java.lang.String"/>
<constructor-arg value="user1" type="java.lang.String"/>
</bean>
也可以通过属性名进行注入值。
<bean id="userConstructor" class="cn.com.demo.User">
<constructor-arg value="1" name="userID"/>
<constructor-arg value="user1" name="userName"/>
</bean>
User.java
package cn.com.demo;
public class User {
private String userID;
private String userName;
public User(String userID, String userName) {
this.userID = userID;
this.userName = userName;
}
@Override
public String toString() {
return "User [userID=" + userID + ", userName=" + userName + "]";
}
}
测试类TestConstructor.java
package cn.com.test;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.com.demo.User;
public class TestConstructor {
private ClassPathXmlApplicationContext ac;
@Before
public void before() {
ac = new ClassPathXmlApplicationContext("*/applicationContext.xml");
}
@Test
public void test() {
try {
User user = (User) ac.getBean("userConstructor");
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果
3.setter方法注入
通过JavaBean属性注射依赖关系的做法称为设值方法注入(Setter Injection)。因为方法可以命名,所以setter方法注入在描述性上要比构造方法注入好一些。 另外,setter方法可以被继承,允许设置默认值,而且有良好的IDE支持。缺点当然就是对象无法在构造完成后马上进入就绪状态。其实,这些操作都是由IoC容器来做的,我们所要做的,就是调用IoC容器来获得对象而已。
例1 Setter注入Bean
applicationContext.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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<!-- setter注入bean -->
<bean id="user" class="cn.com.demo.User"/>
<bean id="personSetter" class="cn.com.demo.Person">
<!--构造注入user-->
<property name="user" ref="user"/>
</bean>
</beans>
User.java
package cn.com.demo;
public class User {
public void getUser() {
System.out.println("这是setter注入bean");
}
}
Person .java
package cn.com.demo;
public class Person {
private User user;
//setter方式注入bean
public void setUser(User user) {
this.user = user;
};
public void getPerson() {
user.getUser();
}
}
测试类TestSetter.java
package cn.com.test;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.com.demo.Person;
public class TestSetter {
private ClassPathXmlApplicationContext ac;
@Before
public void before() {
ac = new ClassPathXmlApplicationContext("*/applicationContext.xml");
}
@Test
public void test() {
try {
Person person = (Person) ac.getBean("personSetter");
person.getPerson();
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果
例2 Setter注入字面量
applicationContext.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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<!-- setter注入字面量 -->
<bean id="userSetter" class="cn.com.demo.User">
<property name="userID" value="2"/>
<property name="userName" value="user2"/>
</bean>
</beans>
User.java
package cn.com.demo;
public class User {
private String userID;
private String userName;
public String getUserID() {
return userID;
}
public void setUserID(String userID) {
this.userID = userID;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserName() {
return userName;
}
@Override
public String toString() {
return "UserID = " + userID + ", UserName = " + userName;
}
}
测试类TestSetter.java
package cn.com.test;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.com.demo.User;
public class TestSetter {
private ClassPathXmlApplicationContext ac;
@Before
public void before() {
ac = new ClassPathXmlApplicationContext("*/applicationContext.xml");
}
@Test
public void test() {
try {
User user = (User) ac.getBean("userSetter");
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果
例3 Setter方法注入集合
applicationContext.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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<!-- setter注入集合 -->
<bean id="userSetter" class="cn.com.demo.User">
<!-- Set集合的属性注入 -->
<property name="set">
<set>
<value>set1</value>
<value>set2</value>
<value>set3</value>
</set>
</property>
<!-- List集合的属性注入 -->
<property name="list">
<list>
<value>list1</value>
<value>list2</value>
<value>list3</value>
</list>
</property>
<!-- 数组的注入 -->
<property name="array">
<list>
<value>array1</value>
<value>array1</value>
<value>array1</value>
</list>
</property>
<!-- Map集合的属性注入 -->
<property name="map">
<map>
<entry key="key1" value="map1"></entry>
<entry key="key2" value="map2"></entry>
<entry key="key3" value="map3"></entry>
</map>
</property>
</bean>
</beans>
User.java
package cn.com.demo;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class User {
private Set<String> set;
private List<String> list;
private Map<String, String> map;
private String[] array;
public Set<String> getSet() {
return set;
}
public void setSet(Set<String> set) {
this.set = set;
}
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
public Map<String, String> getMap() {
return map;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public String[] getArray() {
return array;
}
public void setArray(String[] array) {
this.array = array;
}
@Override
public String toString() {
return "User [set=" + set + ", list=" + list + ", map=" + map + ", array=" + Arrays.toString(array) + "]";
}
}
测试类TestSetter.java
package cn.com.test;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.com.demo.User;
public class TestSetter {
private ClassPathXmlApplicationContext ac;
@Before
public void before() {
ac = new ClassPathXmlApplicationContext("*/applicationContext.xml");
}
@Test
public void test() {
try {
User user = (User) ac.getBean("userSetter");
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果
4.基于注解的注入
spring容器对于Bean的创建和对象属性的依赖注入提供了注解的支持,让我们在开发中能够更加便捷的实现对象的创建和对象属性的依赖注入。
4.1 常见的注解
- @Autowired是自动注入,自动从spring的上下文找到合适的bean来注入。
- @Resource用来指定名称自动注入。
- @Qualifier和@Autowired配合使用,指定bean的名称。
- @Service,@Controller,@Repository分别标记类是Service层类,Controller层类,数据存储层的类,spring扫描注解配置时,会标记这些类要生成bean。
- @Component是一种泛指,标记类是组件,spring扫描注解配置时,会标记这些类要生成bean。
4.2 注解分类
对于Bean属性的依赖注入分为两类:
一类是对于属性是String类型或者基本数据类型Spring容器提供了@Value这个注解,另一类是对于属性是对象的提供了@Autowired和@Resource这两个注解。其中,@Autowired这个注解是spring框架自带的注解,而@Resource(javax.annotation.Resource)这个注解是javax扩展包中注解规范的一种,而spring对这一注解提供了支持。
4.3 基于注解注入实例
注:使用注解注入需要开启注解扫描
<!-- 启用注释驱动自动注入 -->
<context:annotation-config/>
<!-- 开启注解扫描 -->
<context:component-scan base-package="cn.com.demo"></context:component-scan>
applicationContext.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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<!-- 启用注释驱动自动注入 -->
<!-- <context:annotation-config/> -->
<!-- 配置自动扫描的包 -->
<context:component-scan base-package="cn.com.demo"></context:component-scan>
</beans>
例1 使用@Component注解
User.java
package cn.com.demo;
import org.springframework.stereotype.Component;
@Component
public class User {
public User() {
System.out.println("这是User的一个无参构造函数");
}
}
测试类TestAnnotation.java
package cn.com.test;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAnnotation {
@Test
public void test() {
try {
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("*/applicationContext.xml");
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果
例2 bean属性为String类型及基本数据类型的依赖注入
User.java
package cn.com.demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component(value = "userAnnotation")
public class User {
@Value("1")
private String userID;
@Value("user1")
private String userName;
public String getUserID() {
return userID;
}
public String getUserName() {
return userName;
}
@Override
public String toString() {
return "UserID = " + userID + ", UserName = " + userName;
}
}
注:@Component(value = “userAnnotation”) ,其中value指定的是bean的id,另外对于注解方式实现的依赖注入,bean的属性无需再提供setter方法。
测试类TestAnnotation.java
package cn.com.test;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.com.demo.User;
public class TestAnnotation {
private ClassPathXmlApplicationContext ac;
@Before
public void before() {
ac = new ClassPathXmlApplicationContext("*/applicationContext.xml");
}
@Test
public void test() {
try {
User user = (User) ac.getBean("userAnnotation");
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果
例3 bean属性为java对象的依赖注入
对于bean属性为java对象的依赖注入,分为两种一种是byName类型的,一种是byType类型的。而使用的注解分别是@Autowired和@Resource,对于byType类型的两者的使用没有区别,但是对于byName类型的@Autowired要使用联合注解@Qualifier,所以说使用@Resource较为简单。byName就是通过Bean的id或者name,byType就是按Bean的Class的类型。
例3.1 byName类型对bean属性为java对象的依赖注入
User.java
package cn.com.demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component(value = "userAnnotation")
public class User {
@Value("2")
private String userID;
@Value("user2")
private String userName;
public String getUserID() {
return userID;
}
public String getUserName() {
return userName;
}
@Override
public String toString() {
return "UserID = " + userID + ", UserName = " + userName;
}
}
Person.java
package cn.com.demo;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
@Component(value = "personAnnotation")
public class Person {
@Resource(name = "userAnnotation")
private User user;
public User getUser() {
return user;
}
}
测试类TestAnnotation.java
package cn.com.test;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.com.demo.Person;
public class TestAnnotation {
private ClassPathXmlApplicationContext ac;
@Before
public void before() {
ac = new ClassPathXmlApplicationContext("*/applicationContext.xml");
}
@Test
public void test() {
try {
Person person = (Person) ac.getBean("personAnnotation");
System.out.println(person.getUser());
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果
例3.2 byType类型对bean属性为java对象的依赖注入
User.java
package cn.com.demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class User {
@Value("3")
private String userID;
@Value("user3")
private String userName;
public String getUserID() {
return userID;
}
public String getUserName() {
return userName;
}
@Override
public String toString() {
return "UserID = " + userID + ", UserName = " + userName;
}
}
Person.java
package cn.com.demo;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
@Component(value = "personAnnotation")
public class Person {
@Resource
private User user;
public User getUser() {
return user;
}
}
测试类TestAnnotation.java
package cn.com.test;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.com.demo.Person;
public class TestAnnotation {
private ClassPathXmlApplicationContext ac;
@Before
public void before() {
ac = new ClassPathXmlApplicationContext("*/applicationContext.xml");
}
@Test
public void test() {
try {
Person person = (Person) ac.getBean("personAnnotation");
System.out.println(person.getUser());
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果
5.静态工厂方法注入bean(不常用)
调用静态工厂方法创建 bean 是将对象创建的过程封装到静态方法中 , 当客户端需要对象时 , 只需要简单地调用静态方法 , 而不需要关心创建对象的细节。要声明通过静态方法创建的Bean,需要在Bean的class属性里指定拥有该工厂的方法的类,同时在factory-method属性里指定工厂方法的名称。最后,使用元素为该方法传递方法参数。
下面为一个静态工厂方法注入bean的例子:
目录结构
applicationContext.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<!-- 静态工厂 -->
<!--class要写工厂的类;factory-method要写工厂类中用于创建bean的方法-->
<bean id="userStatic" class="cn.com.demo.StaticFactory" factory-method="getUser">
<constructor-arg name="userID" value="1"/>
<constructor-arg name="userName" value="user1"/>
</bean>
</beans>
StaticFactory.java
package cn.com.demo;
import cn.com.entity.User;
public class StaticFactory {
public static User getUser(String userID, String userName) {
User user = new User(userID, userName);
return user;
}
}
User.java
package cn.com.entity;
public class User {
private String userID;
private String userName;
public User(String userID, String userName) {
this.userID = userID;
this.userName = userName;
}
public String getUserID() {
return userID;
}
public void setUserID(String userID) {
this.userID = userID;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
@Override
public String toString() {
return "UserID = " + userID + ", UserName = " + userName;
}
}
测试类TestStaticFactory.java
package cn.com.test;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.com.entity.User;
public class TestStaticFactory {
private ClassPathXmlApplicationContext ac;
@Before
public void before() {
ac = new ClassPathXmlApplicationContext("*/applicationContext.xml");
}
@Test
public void test() {
try {
User user = (User) ac.getBean("userStatic");
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果
6.实例工厂方法注入bean(不常用)
将对象的创建过程封装到另外一个对象实例的方法里。当客户端需要请求对象时 , 只需要简单的调用该实例方法而不需要关心对象的创建细节。
- 在Bean的factory-bean属性里指定拥有该工厂方法的Bean。
- 在factory-method属性指定该工厂方法的名称。
- 使用constructor-arg元素为工厂方法传递方法参数。
下面为一个实例工厂方法注入bean的例子:
目录结构
applicationContext.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<!--实例工厂方法是先将工厂实例化-->
<bean id="instanceFactory" class="cn.com.demo.InstanceFactory"/>
<bean id="userInstance" factory-bean="instanceFactory" factory-method="getUser">
<constructor-arg name="userID" value="2"/>
<constructor-arg name="userName" value="user2"/>
</bean>
</beans>
InstanceFactory.java
package cn.com.demo;
import cn.com.entity.User;
public class InstanceFactory {
public User getUser(String userID, String userName) {
User user = new User(userID, userName);
return user;
}
}
User.java
package cn.com.entity;
public class User {
private String userID;
private String userName;
public User(String userID, String userName) {
this.userID = userID;
this.userName = userName;
}
public String getUserID() {
return userID;
}
public void setUserID(String userID) {
this.userID = userID;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
@Override
public String toString() {
return "UserID = " + userID + ", UserName = " + userName;
}
}
测试类TestStaticFactory.java
package cn.com.test;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.com.entity.User;
public class TestStaticFactory {
private ClassPathXmlApplicationContext ac;
@Before
public void before() {
ac = new ClassPathXmlApplicationContext("*/applicationContext.xml");
}
@Test
public void test2() {
try {
User user = (User) ac.getBean("userInstance");
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果