本文共 4976 字,大约阅读时间需要 16 分钟。
常用的注入方式有四种:
1. 属性注入 2. 构造方法注入 3. 工厂方法注入 4. 注解注入 下面先定义我们后面用到的POJO类:package test;public class User { private String name; private String gender; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } @Override public String toString() { return "User [name=" + name + ", gender=" + gender + "]"; }}
属性注入(set方法注入)对Bean有两点要求:
1. 提供一个默认的构造函数 2. 为需要注入的属性提供set方法 配置示例如下: xml文件配置:测试函数:
public static void main(String args[]){ ApplicationContext atc = new ClassPathXmlApplicationContext("spring.xml"); User user = (User) atc.getBean("user"); System.out.println(user);//print User [name=zeng, gender=male]}
而如果我们把POJO中的getName方法去掉,结果不变,但setName方法删掉,我们再运行程序,会看到如下报错信息:
Exception in thread “main” org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘user’ defined in class path resource [spring.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property ‘name’ of bean class [test.User]: Bean property ‘name’ is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
显然,我们的属性注入,set方法是必不可少的。
先在User POJO中新增带参构造方法和age属性:
private Integer age; get and set ... public User(String name, Integer age) { this.name = name; this.age = age; } //这里需特别注意的是,我们定义了带参的构造函数,JVM就不会因为没有定义构造函数为我们创建默认的构造函数了,因此这里我们需要自己重新定义
在xml文件定义Bean:
调用测试函数:
public static void main(String args[]){ ApplicationContext atc = new ClassPathXmlApplicationContext("spring.xml"); User user = (User) atc.getBean("user1"); System.out.println(user.getName() + "——" + user.getAge()); //print zeng1——20}
这时候,我们再稍微修改下xml文件:
同时对应User POJO类新定义构造方法:
public User(String name, String gender, Integer age) { super(); this.name = name; this.gender = gender; this.age = age;}
最后修改测试函数并运行:
public static void main(String args[]){ ApplicationContext atc = new ClassPathXmlApplicationContext("spring.xml"); User user = (User) atc.getBean("user1"); System.out.println(user.getName() + "——" + user.getAge() +"——" +user.getGender()); //print male1——12——zeng}
通过这个有趣的试验,我们发现,当出现重复的类型时,构造函数会根据的定义顺序和构造函数的参数顺序对应入参。即使中间插入了其他类型参数,容器也只会对相同类型的进行顺序注入,下面可辅助验证这个特点:
假如我们去掉中间<constructor-arg type="java.lang.Integer" value="12" ></constructor-arg>
,就会打印male1——null——zeng。
在前面第5点建立了三参数构造函数的基础上,我们在xml文件上编写:
运行测试函数:
public static void main(String args[]){ ApplicationContext atc = new ClassPathXmlApplicationContext("spring.xml"); User user = (User) atc.getBean("user2"); System.out.println(user.getName() + "——" + user.getAge() +"——" +user.getGender()); //print male2——12——zeng2}
注意索引为3的value必须为Integer(与构造函数对应,否则会报错:
注意到我这里是name=“male2”和gender=”zeng2”,即参数值注入是严格根据index来的,且index从0开始算起 关于构造函数注入的优点: 1. 保证一些主要的属性在Bean实例化时就配置好 2. 不需要为每个方法提供Setter方法,减少了类的方法个数,同时还能更好的封装变量,避免外界的错误调用Setter方法 关于构造函数注入的缺点: 1. 如果一个类的属性众多,且我们需要针对不同的属性堆构造特定的构造方法,那么构造函数的数量就会很多(否则需制定特点属性为null,这样可读性也差),而且构造函数本身会变得很庞大臃肿。同时我们还要考虑到配置文件的构造函数参数匹配的歧义问题 2. 构造函数不利于类的继承和扩展,因为子类需要引用到父类复杂的构造函数Could not resolve matching constructor (hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)
)
此方法能更有效地避免歧义产生
因为工厂方法非静态,要调用改方法必须先初始化对象
先定义工厂类:
package test; public class UserFactory { public User createUser(){ User user = new User("zeng3","male3",20); return user; } }
进行Bean配置:
调用测试函数:
public static void main(String args[]){ ApplicationContext atc = new ClassPathXmlApplicationContext("spring.xml"); User user = (User) atc.getBean("user3"); System.out.println(user.getName() +" ——" +user.getGender()+ "——" + user.getAge() ); //print zeng3——male3——20 }
无须另外创建对象,先将createUser方法给为静态,然后将bean配置为:
<bean id="user3" class="test.UserFactory" factory-method="createUser"></bean>
调用测试函数即可得到与上次相同的结果。 这里需要注意的是,静态方法先定义工厂Bean,再配置在id为user3的bean中,而id=user3的bean没有定义class属性。因为它的类的归属在工厂类里判决,而静态工厂方法中,没有了userFactory bean的定义(即不用初始化),但在user3中定义了一个class,这个class指向了工厂类
使用@Autowire实现自动注入,格式如:
@Componentpublic class IdCard{ .....}public class User{ //Autowired默认按类型注入,@required 表明如果找不到对应的bean则为null,但如果设定为true(也是默认值),则要求一定要找到匹配的bean,否则会抛出异常。 //Qualifier常用于容器有一个以上相同类型的Bean,通过指定名字来指定唯一的Bean @Autowired(required = false ) @Qualifier("idCard") private IdCard idCard;//也可以将IdCard配置在xml文件中注入 .....}
@Autowiredpublic void init(@Qualifier(“usar1")User user1,@Qualifier("user2")User user2){ this.user1 = user1; this.user2 = user2;}
转载地址:http://ngall.baihongyu.com/