Simple IOC 容器实现-基于注解
来源:互联网 发布:淘宝货源外国 编辑:程序博客网 时间:2024/04/30 15:37
上一篇文章介绍了如何基于XML文件去实现一个简单的IOC容器。但Spring不仅支持XML文件配置方式,还支持通过注解进行配置,本篇重点介绍如何通过注解来实现一个简单的IOC容器。
使用
首先,看看如何基于注解来进行依赖注入,代码如下:
import com.ricky.framework.ioc.bind.annotation.Inject;import com.ricky.ioc.sample.model.Student;import com.ricky.ioc.sample.service.StudentService;@Bean(id="studentController")public class StudentController { @Inject// @Inject(name="studentService") private StudentService studentService; public String find(long id){ Student stu = studentService.find(id); System.out.println("stu:"+stu); return "fin }}
StudentService接口
import com.ricky.ioc.sample.model.Student;public interface StudentService { public Student find(long id);}
StudentService接口实现类
import com.ricky.framework.ioc.bind.annotation.Bean;import com.ricky.framework.ioc.bind.annotation.Inject;import com.ricky.ioc.sample.dao.StudentDao;import com.ricky.ioc.sample.model.Student;import com.ricky.ioc.sample.service.StudentService;@Bean(id="studentService")public class StudentServiceImpl implements StudentService { @Inject private StudentDao studentDao; @Override public Student find(long id) { return studentDao.find(id); }}
以上使用了两个自定义注解:@Bean 与 @Inject。在 StudentServiceImpl 类上标注了 @Bean 注解,表示该类会交给“容器”处理,IOC容器生成的bean的id为@Bean 注解的id值。在 studentService字段上标注了 @Inject 注解,表示该字段将会被注入进来,而无需 new StudentServiceImpl (),@Inject 注解默认根据字段的名称来查找bean,同时@Inject 注解也支持通过name属性指定bean。
然后,我们需要在beans.xml配置文件中配置 自动注解 属性:
<?xml version="1.0" encoding="UTF-8"?><beans> <!-- 要扫描的包 --> <context:component-scan base-package="com.ricky.ioc.sample" /> <bean id="userDao" class="com.ricky.framework.ioc.dao.UserDaoImpl"></bean> <bean id="userService" class="com.ricky.framework.ioc.service.UserServiceImpl"> <property name="userDao" ref="userDao"></property> </bean> <bean id="userController" class="com.ricky.framework.ioc.controller.UserController"> <property name="userService" ref="userService"></property> </bean></beans>
到此,基于注解的IOC容器已经配置完毕了,跟Spring IOC的使用完全一致,接下来看看这个功能到底是怎样实现的吧!
实现
@Bean注解
import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)@Target({ ElementType.TYPE })@Documentedpublic @interface Bean { // 类似spring配置文件中的bean String id();}
@Inject注解
import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)@Target({ ElementType.FIELD, ElementType.METHOD })@Documentedpublic @interface Inject { public String name() default "";}
最后,我们扫描当前classpath下所有带@Bean注解的类,然后利用反射构造Bean实例对象并完成依赖注入。整个代码如下:
import java.beans.Introspector;import java.beans.PropertyDescriptor;import java.io.IOException;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.util.HashMap;import java.util.List;import java.util.Map;import com.ricky.framework.ioc.bind.annotation.Bean;import com.ricky.framework.ioc.bind.annotation.Inject;import com.ricky.framework.ioc.util.ClassDetector;public class AnnotationIocContainer { protected Map<String, Object> beanInstanceMap = new HashMap<String, Object>(); public void bind(String packageName) { initializeBean(packageName); inject(); } /** * 实例化Bean */ private void initializeBean(String packageName) { try { List<Class<?>> list = new ClassDetector(packageName).detect(Bean.class);; for (Class<?> clazz : list) { Bean beanAnnotation = clazz.getAnnotation(Bean.class); System.out.println("class="+clazz.getName()+",bean_id="+beanAnnotation.id()); Object bean = clazz.newInstance(); //如需通过构造函数注入,需要在此处理 beanInstanceMap.put(beanAnnotation.id(), bean); } } catch (IOException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } private void inject(){ for(String beanName : beanInstanceMap.keySet()){ Object bean = beanInstanceMap.get(beanName); if(bean!=null){ processSetterAnnotation(bean); processFieldAnnotation(bean); } } } /** * 处理field上的注解 * @param bean */ protected void processFieldAnnotation(Object bean){ try { Field[] fields = bean.getClass().getDeclaredFields(); for(Field field : fields){ if(field!=null && field.isAnnotationPresent(Inject.class)){ Inject resource = field.getAnnotation(Inject.class); String name = resource.name(); Object injectBean = null; if(name!=null&&!"".equals(name)){ injectBean = beanInstanceMap.get(name); }else{ for(String key : beanInstanceMap.keySet()){ //判断当前属性所属的类型是否在配置文件中存在 if(field.getType().isAssignableFrom(beanInstanceMap.get(key).getClass())){ //获取类型匹配的实例对象 injectBean = beanInstanceMap.get(key); break; } } } if(injectBean!=null){ //允许访问private字段 field.setAccessible(true); //把引用对象注入属性 field.set(bean, injectBean); }else{ System.out.println("field inject failed,name="+name); } } } } catch (Exception e) { e.printStackTrace(); } } /** * 处理set方法上的注解 * @param bean */ protected void processSetterAnnotation(Object bean){ try { //获取bean的属性描述器 PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors(); for(PropertyDescriptor pd : ps){ Method setter = pd.getWriteMethod(); if(setter!=null && setter.isAnnotationPresent(Inject.class)){ //获取当前注解,并判断name属性是否为空 Inject resource = setter.getAnnotation(Inject.class); String name = resource.name(); Object injectBean = null; if(name!=null&&!"".equals(name)){ injectBean = beanInstanceMap.get(name); }else{ //如果当前注解没有指定name属性,则根据类型进行匹配 for(String key : beanInstanceMap.keySet()){ if(pd.getPropertyType().isAssignableFrom(beanInstanceMap.get(key).getClass())){ injectBean = beanInstanceMap.get(key); break; } } } if(injectBean!=null){ //允许访问private方法 setter.setAccessible(true); //把引用对象注入属性 setter.invoke(bean, injectBean); }else{ System.out.println("setter inject failed,name="+name); } } } } catch (Exception e) { e.printStackTrace(); } }}
0 0
- Simple IOC 容器实现-基于注解
- Simple IOC 容器实现-基于XML方式
- Spring(四)基于注解配置IOC容器&基于注解实现声明式事务
- Spring(四)基于注解配置IOC容器&基于注解实现声明式事务
- 【理论】Spring IOC容器:注解
- 基于微软Unity的IoC容器(DI)实现
- IoC容器实现读书笔记
- Spring IOC容器实现
- 手动实现IOC容器
- IoC容器的实现
- Spring实现IOC容器
- Spring IOC容器实现
- IOC容器的实现
- 使用注解实现IoC
- 基于注解的IOC配置
- 使用注解来构造IoC容器
- 使用注解来构造IoC容器
- 使用注解来构造IoC容器
- tcp 的一些问题
- poj2482 Stars in Your Window(成段更新+扫描线)
- microstation level2 0507
- iOS 属性声明在@implementation里与extension里的区别
- stl中的tuple(tie)
- Simple IOC 容器实现-基于注解
- BZOJ 3514 Codechef MARCH14 GERALD07加强版
- Excel错误“不能将对象移到工作表外”解决方法
- Android API之android.widget.Filterable
- linux fedora23 相关操作
- 个人对Spring @Scope("prototype")的一些理解
- 【C程序设计语言(第二版)学习】单词计数 方法
- TCP建立连接需要三步握手的原因
- JSOI2016 Round2 游记