Spring第七弹—依赖注入之注解方式注入及编码解析@Resource原理
注入依赖对象可以采用手工装配或自动装配,在实际应用中建议使用手工装配,因为自动装配会产生未知情况,开发人员无法预见最终的装配结果。
手工装配依赖对象
手工装配依赖对象,在这种方式中又有两种编程方式
- 在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)处理器:
Java
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);
}
}
|
Spring第七弹—依赖注入之注解方式注入及编码解析@Resource原理的更多相关文章
- EJB通过注解方式注入并使用其他EJB或者服务、配置JBoss数据源
通过注解方式注入并使用其他EJB或者服务 真实项目EJB对象很多,EJB之间也可以互相调用, 在项目HelloWorld下新建接口Other在cn.hqu.ejb3下: public interfac ...
- Spring声明式事务管理(基于注解方式实现)
----------------------siwuxie095 Spring 声明式事务管理(基于注解方式实现) 以转 ...
- EJB通过注解方式注入并使用其它EJB或者服务、配置JBoss数据源
版权声明:本文为博主原创文章,转载请注明出处. https://blog.csdn.net/Jerome_s/article/details/37103171 通过注解方式注入并使用其他EJB或者服务 ...
- Spring第六弹—-依赖注入之使用构造器注入与使用属性setter方法注入
所谓依赖注入就是指:在运行期,由外部容器动态地将依赖对象注入到组件中. 使用构造器注入 1 2 3 4 <constructor-arg index=“0” type=“java.lang. ...
- Spring 依赖注入控制反转实现,及编码解析(自制容器)
定义: 在运行期,由外部容器动态的将依赖对象动态地注入到组件中. 两种方式: 手工装配 -set方式 -构造器 -注解方式 自动装配(不推荐) 1利用构造器 2set方法注入 dao: package ...
- spring注解方式注入
1.通过Resource注入 1.在属性上注入 1.默认注入 即不指定spring容器里面的名字 匹配规则:先通过属性的名字查找 再通过属性类型与实现类类型匹配查找 当有两个实现类会报错 2.通过指定 ...
- spring注解方式注入bean
用注解的方式注入bean,spring的配置文件也要增加一些约束和导入注解所在的包 applicationContext.xml <?xml version="1.0" en ...
- 【初识Spring】对象(Bean)实例化及属性注入(注解方式)
通过xml的方式进行对象的实列化或属性注入或许有一些繁琐,所以在开发中常用的方式更多是通过注解的方式实现对象实例化和属性注入的. 开始之前 1.导入相关的包(除了导入基本的包还要导入aop的包): 创 ...
- Spring总结四:IOC和DI 注解方式
首先我们要了解注解和xml配置的区别: 作用一样,但是注解写在Bean的上方来代替我们之前在xml文件中所做的bean配置,也就是说我们使用了注解的方式,就不用再xml里面进行配置了,相对来说注解方式 ...
随机推荐
- 关于ajax跨域的一些说说
跨域:跨当然是跨过去,域当然是别的服务器 (说白点就是去别服务器上取东西) 只要协议.域名.端口有任何一个不同,都被当作是不同的域 ajax 是一种请求响应无刷新技术(xmlhttqrequest对象 ...
- javascript jquery数组操作小结
----------------------------------------------------------定义数组-------------------------------------- ...
- vue-cli打包构建时常见的报错解决方案
报错1:vue-cli项目本地npm run dev启动后,chrome打开是空白页 解决方案:将config下的index.js中的assetsPublicPath路径都设置为‘/’绝对路径 报错2 ...
- boost实用工具:typeof库 BOOST_TYPE BOOST_AUTO
boost::typeof库中使用宏BOOST_TYPE和BOOST_AUTO来模拟C++11关键字typeof和auto C++ Code 123456789101112131415161718 ...
- string类(一、string基础)
string基础 1.字符串常量具备字符串池特性. 字符串常量在创建前,首先在字符串池中查找是否存在相同文本. 如果存在,则直接返回该对象引用:若不存在,则开辟空间存储. 目的:提高内存利用率. 2. ...
- android APP上线前,应该准备的东西
这里给出一些主流的应用市场名单,有些可能已经不行了,自己找一找,很容易的: 应用市场图-1
- 【BZOJ1217】[HNOI2003]消防局的设立 树形DP
[BZOJ1217][HNOI2003]消防局的设立 Description 2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地.起初为了节约材料,人类只修建了n-1条道路来连接这些基地, ...
- js 正则 exec() 和 match() 数据抽取
js 的正则表达式平常用的不多,但以前抽取数据的时候用到过,主要是有这样的需求: var text='<td class="data">2014-4-4</td& ...
- Python全栈day14(集合)
一,集合 1,集合由不同元素组成 2,无序 3,集合中元素必须是不可变类型 二,定义集合 1,s = {1,2,3,4,5} 2,s = set(hello)以迭代的方式生成集合 s = set(&q ...
- 搜索R包和查看包的技巧
1.R怎么搜包 # 安装sos包 install.packages("sos") # 导入sos包 library(sos) # 使用函数findFn() 函数里面传入关键字来搜索 ...