博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
TeaFramework——IOC容器实现(一)
阅读量:6905 次
发布时间:2019-06-27

本文共 4380 字,大约阅读时间需要 14 分钟。

  hot3.png

    Spring的IOC/DI让层与层之间解耦,让接口和实现类不必强依赖,提高程序的扩展性和对需求的适应性。TeaFramework也提供了一个IOC容器,帮我们来生成实例,那么具体设计是什么样的呢?请往下看。

    纯注解以其简单的优势迅速得到广大程序员的青睐,那么这里还是以注解的方式来标示bean和注入bean。TeaFramework中标示bean的注解有两种:@Component、@TeaDao。

    @Component用于控制层和service层.

    @TeaDao用于数据访问层

    @Component包含两个属性,分别标示bean的name、生成对象的模式(单例、原型,默认是单例),代码如下:

@Target({ ElementType.TYPE })@Retention(RetentionPolicy.RUNTIME)public @interface Component {	public String value() default "";	public Scope scope() default Scope.singleton;}

    接下来是注入了,注入又分两种:ByName和ByType,那么注解里只需要一个参数即可搞定,当传入beanName时是按ByName注入,否则按ByType注入。

@Target({ ElementType.FIELD })@Retention(RetentionPolicy.RUNTIME)public @interface Inject {	public String value() default "";}

    那么这样一来我们的代码变得很简洁,控制层代码可以这样写

@Componentpublic class UserController {	@Inject	private UserService userService;}

    service层代码可以这样写

@Componentpublic class UserServiceImpl implements UserService {	@Inject	private UserDao userDao;	@Override	public User addUser(User user) {		userDao.addUser(user);		return userDao.getUserById(user.getId());	}}

    数据访问层代码可以这样写

@TeaDaopublic interface UserDao {	@GetPrimaryKey(sql = "select s_users.nextval from dual", primaryKeyProperty = "id")	@SQL("insert into users(id,username,password) values(#id#,#username#,#password#)")	public void addUser(User user);	@SQL("select * from users where id=#id#")	public User getUserById(Long id);}

    接下来看第二个问题,怎么把bean装进Bean容器呢?这里需要定义两个Map,一个是beanName和对象之间的映射,另一个是beanType和bean List的映射,具体代码如下:

public class BeanContainer {	private static BeanContainer instance;	private static Map
, List
> CLASS_BEAN_MAPPING = new ConcurrentHashMap
, List
>(200); private static Map
NAME_BEAN_MAPPING = new ConcurrentHashMap
(200); private BeanContainer() { } public synchronized static BeanContainer getInstance() { if (instance == null) { instance = new BeanContainer(); } return instance; } public boolean contains(String beanName) { return NAME_BEAN_MAPPING.containsKey(beanName); } public void putBean(Class
beanClass, Object object) { if (CLASS_BEAN_MAPPING.get(beanClass) == null) { List
list = new ArrayList(); list.add(object); CLASS_BEAN_MAPPING.put(beanClass, list); } else { CLASS_BEAN_MAPPING.get(beanClass).add(object); } } public void putBean(String beanName, Object object) { NAME_BEAN_MAPPING.put(beanName, object); } public
T getBeanByName(String beanName) { return (T) NAME_BEAN_MAPPING.get(beanName); } public
List
getBeansByType(Class
beanClass) { return (List
) CLASS_BEAN_MAPPING.get(beanClass); } public void inject() { for (Map.Entry
entry : NAME_BEAN_MAPPING.entrySet()) { injectProperties(entry.getValue()); } } private void injectProperties(Object bean) { List
result = new ArrayList
(); findAllField(bean.getClass(), result); for (Field field : result) { Inject inject = field.getAnnotation(Inject.class); if (inject != null) { field.setAccessible(true); Object object = null; if (!"".equals(inject.value())) {// id注入 object = NAME_BEAN_MAPPING.get(inject.value()); if (object == null) { throw new TeaInjectException("没找到beanName为" + inject.value() + "的Bean"); } } else { List
list = CLASS_BEAN_MAPPING.get(field.getGenericType());// 类型注入 if (list == null || list.size() == 0) { throw new TeaInjectException("没找到类型为" + field.getGenericType().getTypeName() + "的Bean"); } else if (list.size() > 1) { throw new TeaInjectException("存在多个类型为" + field.getGenericType().getTypeName() + "的Bean"); } object = list.get(0); } if (object == null) { throw new TeaInjectException("没找到对应bean"); } try { field.set(bean, object); } catch (Exception e) { throw new TeaInjectException(e); } } } } private void findAllField(Class
clazz, List
result) { Field[] fields = clazz.getDeclaredFields(); if (fields != null && fields.length > 0) { for (int i = 0; i < fields.length; i++) { result.add(fields[i]); } } Class
superclass = clazz.getSuperclass(); if (superclass != null && !java.lang.Object.class.equals(superclass)) { findAllField(superclass, result); } }}

    上面有个重载的putBean方法,一个是把<beanName,对象>放进Map<String, Object>,另一个是对象按照类型映射到List,即Map<Class<?>, List<Object>>。

    injectProperties则是注入属性的具体实现了,如果@Inject的value不为空串,则是根据beanName注入,否则则是根据type注入,ByType注入做了一个特殊处理,就是如果一个Type下有很多实例,拿第一个注入,这里有两个功能是没有实现的属性为集合时注入的场景、原型模式下产生实例的场景,后期可以补上。

    这样就很简易了的实现了IOC容器和依赖注入,那么容器在启动时要扫描哪些包、对象是怎么实例化放进Map的?请关注TeaFramework——IOC容器实现(二)

     项目地址:

     博客:

转载于:https://my.oschina.net/u/1778239/blog/1577025

你可能感兴趣的文章