注入依賴對象可以采用手工裝配或自動裝配,在實際應用中建議使用手工裝配,因為自動裝配會產生未知情況,開發人員無法預見最終的裝配結果。
手工裝配依賴對象
手工裝配依賴對象,在這種方式中又有兩種編程方式
- 在xml配置文件中,通過在bean節點下配置,上邊博客已經講解,再次不在綴余。
- 在java代碼中使用@Autowired或@Resource注解方式進行裝配。但我們需要在xml配置文件中配置以下信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<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
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config/>
</beans>
|
PS:
1
|
<context:annotation-config/>
|
這個配置隱式注冊了多個對注解進行解析處理的處理器:AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,PersistenceAnnotationBeanPostProcessor,RequiredAnnotationBeanPostProcessor
PS:之前我寫過注解原理的博客,再此多說一句,注解本身和xml一樣都是用於配置的,本身並不能干活,它之所以能干活,是因為它背后存在着處理器(也就是對應api)。
PS: 需要引入common-annotations.jar文件。
@Autowired和@Resource注解詳解
在java代碼中使用@Autowired或@Resource注解方式進行裝配,這兩個注解的區別是:@Autowired 默認按類型裝配,@Resource默認按名稱裝配,當找不到與名稱匹配的bean才會按類型裝配。
1
2
3
4
5
6
|
@Autowired
private PersonDao personDao;//用於字段上
@Autowired
public void setOrderDao(OrderDao orderDao) {//用於屬性的setter方法上
this.orderDao = orderDao;
}
|
@Autowired注解是按類型裝配依賴對象,默認情況下它要求依賴對象必須存在,如果允許null值,可以設置它required屬性為false。如果我們想使用按名稱裝配,可以結合@Qualifier注解一起使用。如下:
1
2
|
@Autowired @Qualifier("personDaoBean")
private PersonDao personDao;
|
@Resource注解和@Autowired一樣,也可以標注在字段或屬性的setter方法上,但它默認按名稱裝配。名稱可以通過@Resource的name屬性指定,如果沒有指定name屬性,當注解標注在字段上,即默認取字段的名稱作為bean名稱尋找依賴對象,當注解標注在屬性的setter方法上,即默認取屬性名作為bean名稱尋找依賴對象。
1
2
|
@Resource(name=“personDaoBean”)
private PersonDao personDao;//用於字段上
|
注意:如果沒有指定name屬性,並且按照默認的名稱仍然找不到依賴對象時, @Resource注解會回退到按類型裝配。但一旦指定了name屬性,就只能按名稱裝配了。
PS:@Resource在jdk中已經存在,不屬於Spring,所以盡量使用這個注解。
編碼剖析@Resource的原理:
自定義注解(模仿@Resource):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
package zmcSpring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.dom4j.Element;
/*
* 現在沒法工作,只是一些配置信息
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD})
public @interface zmcResource {
public String name() default "";
}
|
PersonSevicebean:
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
|
package zmc;
import dao.PersonDao;
import zmcSpring.zmcResource;
import zmcjk.PersonService;
public class PersonServicebean implements PersonService {
private String name;
private PersonDao personDao ;
public PersonServicebean(){
}
public PersonServicebean(String name, PersonDao personDao) {
super();
this.name = name;
this.personDao = personDao;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public PersonDao getPersonDao() {
return personDao;
}
@zmcResource
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
public void save(){
personDao.add();
}
}
|
自定義注解(zmcResource)處理器:
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
|
package zmcSpring;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;
/*
* 簡單模擬Spring容器
*/
public class ZmcClassPathXMLApplicationContext {
private List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>();
private Map<String,Object> sigletons = new HashMap<String,Object>();
public ZmcClassPathXMLApplicationContext(String fileName){
this.readXML(fileName);
this.instanceBeans();
this.annotationInject();
this.injectObject();//依賴注入
}
/*
* 暫且把zmcResouce處理器寫在這里
*/
private void annotationInject() {
for(String beanName: sigletons.keySet()){
Object bean =sigletons.get(beanName);
if(bean!=null){
try{
PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
for(PropertyDescriptor properdesc : ps){
Method setter = properdesc.getWriteMethod();//獲得屬性的setter方法
Object obj = null;
if(setter!=null&&setter.isAnnotationPresent(zmcResource.class)){//判斷是否存在zmcResource注解
zmcResource zmc = setter.getAnnotation(zmcResource.class);
if(zmc.name()!=null&&!"".equals(zmc.name())){
obj = sigletons.get(zmc.name());
}else{//沒有設置name屬性,即取得屬性名稱
obj = sigletons.get(properdesc.getName());
if(obj==null){//這時按類型
for(String beanname: sigletons.keySet()){
if(properdesc.getPropertyType().isAssignableFrom(sigletons.get(beanname).getClass())){//兩者類型是否匹配,前者類型是否是后者的父類或接口
obj=sigletons.get(beanname);
break;
}
}
}
}
setter.invoke(bean, obj);
}
}
Field[] fileds = bean.getClass().getDeclaredFields();
for(Field field : fileds){
if(field.isAnnotationPresent(zmcResource.class)){
zmcResource zmc =field.getAnnotation(zmcResource.class);
Object obj = null;
if(zmc.name()!=null&&!"".equals(zmc.name())){
obj = sigletons.get(zmc.name());
}else{
obj = sigletons.get(field.getName());
if(obj==null){
for(String key : sigletons.keySet()){
if(field.getType().isAssignableFrom(sigletons.get(key).getClass())){
obj = sigletons.get(key);
break;
}
}
}
}
field.setAccessible(true);
field.set(bean, obj);
}
}
}
catch (Exception e){
e.printStackTrace();
}
}
}
}
/*
* 為bean屬性注入值
*/
private void injectObject() {
for(BeanDefinition beanDefinition : beanDefines){
Object bean = sigletons.get(beanDefinition.getId());//此時bean還沒有注入
//下面開始進行依賴注入
if(bean!=null){
//取得bean的屬性描述
try {
PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();//bean的屬性
for(PropertyDefinition propertyDefinition : beanDefinition.getProperty()){//用戶配置文件中定義的屬性
for(PropertyDescriptor properdesc : ps){
//判斷配置文件中屬性的名稱和bean中屬性的名稱是否相同
if(propertyDefinition.getName().equals(properdesc.getName())){
Method setter = properdesc.getWriteMethod();
if(setter!=null){
if(propertyDefinition.getRef()!=null&&!"".equals(propertyDefinition.getRef().trim())){
Object value = sigletons.get(propertyDefinition.getRef());
try {
setter.invoke(bean, value);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}//把引用對象注入到屬性
}
}
}
}
}
} catch (IntrospectionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/*
* 完成bean的實例化
*/
private void instanceBeans(){
for(BeanDefinition beanDefinition : beanDefines){
try {
sigletons.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).newInstance());
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/*
* 讀取XMl配置文件
* @param filename
*/
public void readXML(String fileName){
SAXReader saxReader = new SAXReader();
Document document = null;
try{
URL xmlpath = this.getClass().getClassLoader().getResource(fileName);
document = saxReader.read(xmlpath);
Map<String,String> nsMap = new HashMap<String,String>();
nsMap.put("ns", "http://www.springframework.org/schema/beans");//加入命名空間
XPath xsub = document.createXPath("//ns:beans/ns:bean");//創建beans/bean查詢路徑
xsub.setNamespaceURIs(nsMap);//設置命名空間
List<Element> beans = xsub.selectNodes(document);
for(Element element : beans){
String id = element.attributeValue("id");
String clazz = element.attributeValue("class");
BeanDefinition beanDefinition = new BeanDefinition(id,clazz);
XPath propertysub = element.createXPath("ns:property");//nodename(節點名稱):表示選擇該節點的所有子節點
propertysub.setNamespaceURIs(nsMap);
List<Element> propertys = propertysub.selectNodes(element);
for(Element property:propertys){
String propertyName = property.attributeValue("name");
String propertyRef = property.attributeValue("ref");
String propertyValue = property.attributeValue("value");
PropertyDefinition pd = new PropertyDefinition(propertyName, propertyRef,propertyValue);
beanDefinition.getProperty().add(pd);
}
beanDefines.add(beanDefinition);
}
}
catch (Exception e){
e.printStackTrace();
}
}
/*
* 獲取bean實例
*/
public Object getBean(String beanName){
return this.sigletons.get(beanName);
}
}
|