spring深入源码2 简单实现ioc机制 注解形式
上一篇文章 我用了xml形式 实现自己简单版的spring ioc依赖注入 这节主要利用注解形式实现 和上集内容一样 只是加了读取注解的方法。
DAO接口
public interface PersonDao {
public void add();
}实现类
package cn.leam.dao.impl;
import cn.leam.dao.PersonDao;
public class PersonDaoBean implements PersonDao {
public void add(){
System.out.println("执行add()方法");
}
}服务接口
public interface PersonService {
public void save();
} 服务实现类
public class PersonServiceBean implements PersonService {
@LeamResource private PersonDao personDao;
public PersonDao getPersonDao() {
return personDao;
}
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
public void save(){
personDao.add();
}
}<?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
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/>
<bean id="personDao" class="cn.leam.dao.impl.PersonDaoBean"></bean>
<bean id="personService" class="cn.leam.service.impl.PersonServiceBean">
<!--这里把xml定义的属性去掉 我们使用注解获取
<property name="personDao" ref="personDao"></property> -->
</bean>
</beans>下面模拟spring对xml配置的类进行实例化
存放属性的对象
public class prosDefinition {
private String name;
private String ref;
public ProsDefinition(String name, String ref) {
this.name = name;
this.ref = ref;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRef() {
return ref;
}
public void setRef(String ref) {
this.ref = ref;
}
}存放bean的 对象
public class Definition {
private String id;
private String className;
private List<ProsDefinition> propertys = new ArrayList<ProsDefinition>();
public Definition(String id, String className) {
this.id = id;
this.className = className;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public List<PropertyDefinition> getPropertys() {
return propertys;
}
public void setPropertys(List<PropertyDefinition> propertys) {
this.propertys = propertys;
}
}加上注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface LeamResource {
public String name() default "";
} 这里是关键点 所有代码都在这里 使用dom4j 解析xml文件中的bean 并获取id和class 再判断元素中是否有引用元素对其一并获取出来存放才Map中 利用java反射一个一个进行实例化
/**
* 学习版容器
*
*/
public class LeamClassPathXMLApplicationContext {
private List<Definition> beanDefines = new ArrayList<Definition>();
private Map<String, Object> sigletons = new HashMap<String, Object>();
public LeamClassPathXMLApplicationContext(String filename){
this.readXML(filename);
this.instanceBeans();
this.annotationInject();
this.injectObject();
}
/**
* 为bean对象的属性注入值
*/
private void injectObject() {
for(Definition beanDefinition : beanDefines){
Object bean = sigletons.get(beanDefinition.getId());
if(bean!=null){
try {
PropertyDescriptor[] ps =
Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
for(ProsDefinition propertyDefinition : beanDefinition.getPropertys()){
for(PropertyDescriptor properdesc : ps){
if(propertyDefinition.getName().equals(properdesc.getName())){
Method setter = properdesc.getWriteMethod();//获取属性的setter方法
if(setter!=null){
Object value = sigletons.get(propertyDefinition.getRef());
setter.setAccessible(true);
setter.invoke(bean, value);//把引用对象注入到属性
}
break;
}
}
}
} catch (Exception e) {
}
}
}
}
/**
* 完成bean的实例化
*/
private void instanceBeans() {
for(Definition beanDefinition : beanDefines){
try {
if(beanDefinition.getClassName()!=null && !""
.equals(beanDefinition.getClassName().trim()))
sigletons.put(beanDefinition.getId(),
Class.forName(beanDefinition.getClassName()).newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 读取xml配置文件
* @param filename
*/
private 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);//获取文档下所有bean节点
for(Element element: beans){
String id = element.attributeValue("id");//获取id属性值
String clazz = element.attributeValue("class"); //获取class属性值
Definition beanDefine = new Definition(id, clazz);
XPath propertysub = element.createXPath("ns:property");
propertysub.setNamespaceURIs(nsMap);//设置命名空间
List<Element> propertys = propertysub.selectNodes(element);
for(Element property : propertys){
String propertyName = property.attributeValue("name");//元素内部引用的属性也获取
String propertyref = property.attributeValue("ref");
ProsDefinition propertyDefinition = new ProsDefinition(propertyName, propertyref);
beanDefine.getPropertys().add(propertyDefinition);
}
beanDefines.add(beanDefine);
}
}catch(Exception e){
e.printStackTrace();
}
}
/**
* 获取bean实例
* @param beanName
* @return
*/
public Object getBean(String beanName){
return this.sigletons.get(beanName);
}
}
/**
* 通过注解实现注入依赖对象
*/
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方法
//如果是用了注解 将在set方法注入进去
if(setter!=null && setter.isAnnotationPresent(LeamResource.class)){
LeamResource resource = setter.getAnnotation(LeamResource.class);
Object value = null;
if(resource.name()!=null && !"".equals(resource.name())){
value = sigletons.get(resource.name());
}else{
value = sigletons.get(properdesc.getName());
if(value==null){
for(String key : sigletons.keySet()){
if(properdesc.getPropertyType().
isAssignableFrom(sigletons.get(key).getClass())){
value = sigletons.get(key);
break;
}
}
}
}
setter.setAccessible(true);允许访问私有字段
setter.invoke(bean, value);//把引用对象注入到属性
}
}
Field[] fields = bean.getClass().getDeclaredFields();
for(Field field : fields){
if(field.isAnnotationPresent(LeamResource.class)){
LeamResource resource = field.getAnnotation(LeamResource.class);
Object value = null;
if(resource.name()!=null && !"".equals(resource.name())){
value = sigletons.get(resource.name());
}else{
value = sigletons.get(field.getName());
if(value==null){
for(String key : sigletons.keySet()){
if(field.getType().
isAssignableFrom(sigletons.get(key).getClass())){
value = sigletons.get(key);
break;
}
}
}
}
field.setAccessible(true);//允许访问private字段
field.set(bean, value);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}public class SpringTest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
@Test public void instanceSpring(){
LeamClassPathXMLApplicationContext ctx = new
LeamClassPathXMLApplicationContext("beans.xml");
PersonService personService = (PersonService)ctx.getBean("personService");
personService.save();
}
}最终输出
"执行add()方法" 说明实例化成功 否则 出现空指针异常
相关推荐
tianxiaolu 2020-04-06
itjavashuai 2020-07-28
smalllove 2020-07-27
willluckysmile 2020-06-29
TiDBPingCAP 2020-06-21
丽丽 2020-06-11
shenxiuwen 2020-06-10
willluckysmile 2020-06-10
MrFuWen 2020-06-09
yuanye0 2020-06-08
whbing 2020-05-19
yuanye0 2020-05-14
kong000dao0 2020-05-10
方志朋 2020-05-08
somyjun 2020-05-01
suixinsuoyu 2020-04-29
咻pur慢 2020-04-22
吾日五省我身 2020-03-28