先说结论:
Spring使用自动装配时,同一个bean配置文件下,类型为引用的Spring自动装配中,其DI(dependency injection)优先级高于同一个标签中的c命名空间的DI优先级,而P命名空间的优先级高于自动装配。
即
DI(P-namespace) > DI(Autowiring) > DI(C-namespace)
为减少代码篇幅长度,下文中的pojo类中使用了Lombok第三方jar包来简述代码
(Lombok这个神器应该很多小伙伴都知晓,这里作者就不阐述了,假如不知道其实也不影响)
1、P命名空间的使用(Properties)
Spring配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="catttttttt" class="cn.BinGCU.pojo.AninalImpl.Cat" p:name="zhangsanCat" scope="singleton"/> <bean id="doggggg" class="cn.BinGCU.pojo.AninalImpl.Dog" p:name="zhangsanDog" scope="singleton"/>
<bean id="personnnnnn" class="cn.BinGCU.pojo.Person" p:cat-ref="catttttttt" p:dog-ref="doggggg"/>
</beans>
|
pojo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import lombok.Data;
public interface Animal { void shout(); }
@Data public class Cat implements Animal { private String name;
@Override public void shout() { System.out.println("Cat: miao~"); } }
@Data public class Dog implements Animal { private String name;
@Override public void shout() { System.out.println("Dog: bark~"); } }
|
Test:
1 2 3 4
| ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println(context.getBean("catttttttt", Cat.class)); System.out.println(context.getBean("doggggg", Dog.class));
|
Output:
1 2
| Cat(name=zhangsanCat) Dog(name=zhangsanDog)
|
2、C命名空间的使用(Constructor-args)
Spring配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?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:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="catttttttt" class="cn.BinGCU.pojo.AninalImpl.Cat" p:name="lisiCat"/> <bean id="doggggg" class="cn.BinGCU.pojo.AninalImpl.Dog" p:name="lisiDog"/> <bean id="personnnnn" class="cn.BinGCU.pojo.Person" c:cat-ref="catttttttt" c:dog-ref="doggggg"/> </beans>
|
pojo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| import lombok.Data;
public interface Animal { void shout(); }
@Data public class Cat implements Animal { private String name;
@Override public void shout() { System.out.println("Cat: miao~"); } }
@Data public class Dog implements Animal { private String name;
@Override public void shout() { System.out.println("Dog: bark~"); } }
@Data public class Person {
private Cat cat; private Dog dog;
public Person(){}
public Person(Cat cat, Dog dog) { this.cat = cat; this.dog = dog; } }
|
Test:
1 2 3 4
| ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Person personnnnn= context.getBean("personnnnn", Person.class); System.out.println(personnnnn);
|
Output
1
| Person(cat=Cat(name=lisiCat), dog=Dog(name=lisiDog))
|
3、自动装配
Spring配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?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" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config />
<--这里的id(cat和dog)与Person类中的属性名一致,请看下文的pojo定义--> <bean id="cat" class="cn.BinGCU.pojo.AninalImpl.Cat" p:name="wangwuCat"/> <bean id="dog" class="cn.BinGCU.pojo.AninalImpl.Dog" p:name="wangwuDog"/>
<bean id="person" class="cn.BinGCU.pojo.Person" /> </beans>
|
pojo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| import lombok.Data;
public interface Animal { void shout(); }
@Data public class Cat implements Animal { private String name;
@Override public void shout() { System.out.println("Cat: miao~"); } }
@Data public class Dog implements Animal { private String name;
@Override public void shout() { System.out.println("Dog: bark~"); } }
@Data public class Person { @Autowired private Cat cat; @Autowired private Dog dog;
public Person(){}
public Person(Cat cat, Dog dog) { this.cat = cat; this.dog = dog; } public void managePets(){ System.out.println("Manage Dog and Cat"); cat.shout(); dog.shout(); } }
|
Test:
1 2 3 4 5
| ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = context.getBean("person", Person.class); person.managePets(); System.out.println(person);
|
Output
1 2 3 4
| Manage Dog and Cat Cat: miao~ Dog: bark~ Person(cat=Cat(name=wangwuCat), dog=Dog(name=wangwuDog))
|
到目前为止的1/2/3点都是没毛病的,都属于Spring的正常用法
但是下面第4点开始,将让Cat/Dog的bean的id不与Person类中的属性名相同,并同时使用P命名空间与C命名空间
4、搞事情
Spring配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <?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" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config />
<--这里的id(cat和dog)与Person类中的属性名cat和dog一致--> <bean id="cat" class="cn.BinGCU.pojo.AninalImpl.Cat" p:name="zhangsanCat"/> <bean id="dog" class="cn.BinGCU.pojo.AninalImpl.Dog" p:name="zhangsanDog"/>
<--这里的id(catttttttt和doggggg)与Person类中的属性名cat和dog不一致--> <bean id="catttttttt" class="cn.BinGCU.pojo.AninalImpl.Cat" p:name="wangwuCat"/> <bean id="doggggg" class="cn.BinGCU.pojo.AninalImpl.Dog" p:name="wangwuDog"/>
<--这里指定了id为catttttttt的引用,而不是id为cat的引用--> <--那么person的两只宠物到底是叫zhangsanCat,zhangsanDog还是wangwuCat,wangwuDog呢?--> <bean id="person01" class="cn.BinGCU.pojo.Person" p:cat-ref="catttttttt" p:dog-ref="doggggg"/> <bean id="person02" class="cn.BinGCU.pojo.Person" c:cat-ref="catttttttt" c:dog-ref="doggggg"/> </beans>
|
Test:
1 2 3 4 5 6 7 8 9 10 11
| ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person01 = context.getBean("person01 ", Person.class); person01. System.out.println("P命名空间:"); System.out.println(person01 );
Person person02 = context.getBean("person02", Person.class); person02.managePets(); System.out.println("C命名空间:"); System.out.println(person02);
|
Output
1 2 3 4 5 6 7 8 9 10 11
| Manage Dog and Cat Cat: miao~ Dog: bark~ P命名空间: Person(cat=Cat(name=zhangsanCat), dog=Dog(name=zhangsanDog))
Manage Dog and Cat Cat: miao~ Dog: bark~ C命名空间: Person(cat=Cat(name=wangwuCat), dog=Dog(name=wangwuDog))
|
瞧,person02的情况是两只宠物是属于wangwu的,所以自动装配的DI(dependency injection)优先级高于在同一个bean标签下的c命名空间的DI优先级。
而person01的情况,也反映了P命名空间的DI优先级大于自动装配,因为它能不受autowiring影响而成功找到对应的类型引用
所以说在采用自动装配的一个bean配置文件中同时使用p/c命名空间,从安全角度,如果你在没有搞清楚具体能不能这样注入值的情况下这么做,那么此般举动将是危险的。当Spring所自动装配的bean中,有某个属性默认注入值为null,在复杂的业务中,那同样也会引发大问题,更别提实际业务中的bug分析有多么令人头疼了
所以不要想着方便,而在一个需要手动注入、却只有一部分需要自动装配的bean配置中开启 <context:annotation-config />,因为在这种情况c命名空间将被自动装配无效化