热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:模仿Spring实现注解注入

篇首语:本文由编程笔记#小编为大家整理,主要介绍了模仿Spring实现注解注入相关的知识,希望对你有一定的参考价值。 写这个极其蛋疼,我一直在想我

篇首语:本文由编程笔记#小编为大家整理,主要介绍了模仿Spring实现注解注入相关的知识,希望对你有一定的参考价值。


 

写这个极其蛋疼,我一直在想我们用SSM写项目时,写Service和Controller的时候,会给Service和Controller私有属性,比如Service需要dao,Controller需要Service,但是我们没有写过setter方法,而且也没有写带参构造器。那么它是怎么注入的呢?

我绞尽脑汁,用了Field类的 set(Object,Object)办法,发现不能对private修饰的私有属性进行注入,其实我已经很接近答案了。但是!我辗转了一个晚上,才知道setAccessible(boolean)这个方法可以强行干进去。。。

不说了,一会儿还要睡觉,直接上代码。我用的是注解注入的,而且稍微修改了昨晚mapper的代码,最后目录被我改成这样了。。。技术分享

技术分享技术分享

 

把昨晚的DaoProxy改成了DaoFactory。我其实是想写工厂模式的,但是我没有这个经验,现在先把基础功能写起来,后面再看看设计模式改造一下吧。。。

下面这些接受困难的可以先移步

模仿Mybatis用mapper.xml实现Dao层接口的功能

最后DaoProxy被我改成了这样。。。暴露出来的getBean方法里的参数是在xml文件中读取的。。。


package com.yck.yebatis;
import java.io.File;
import java.io.FileFilter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.yck.bean.Function;
import com.yck.bean.MapperBean;
import com.yck.exception.NoConfigFileException;
import com.yck.util.DataUtil;
public class DaoFactory implements BeanFactory
{

private static Map beans;

static
{
configDao();
}


@Override
public Object getBean(String beanName) //暴露获取Bean的方法
{
return beans.get(beanName);
}




private static void configDao() //初始化
{
Map
map = new HashMap();
try
{
File[] files
= getAllFiles();
for(File f:files)
{
MapperBean mapper
= readMapper(f.getPath());
Object obj
= implDao(mapper);
map.put(mapper.getProxyName(), obj);
}
}
catch (NoConfigFileException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}

beans
= map;
}



/**
* 得到所有的mapper.xml文件
*
@return
*
@throws NoConfigFileException
*/
private static File[] getAllFiles() throws NoConfigFileException
{
File configPath
= new File("src/mapper"); //为了简单起见,规定写在该目录下
FileFilter fileFilter = new FileFilter() //写过滤器,筛选后缀为.xml的文件
{

@Override
public boolean accept(File pathname)
{
String str
= pathname.getName().toLowerCase();
if(str.endsWith(".xml"))
return true;
return false;
}
};

File[] files
= configPath.listFiles(fileFilter);
if(files == null || files.length == 0) //如果没有这样的文件,抛出异常
{
files
= null;
throw new NoConfigFileException();
}
return files;
}


/**
* 通过读取配置文件实现dao接口
*
@param path
*
@return
*/
private static Object implDao(MapperBean mapper)
{
ClassLoader classLoader
= DaoFactory.class.getClassLoader();
Class
interfaze = null;
try
{
interfaze
= classLoader.loadClass(mapper.getInterfaceName()); //加载一个接口类
} catch (ClassNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}

/**
* 下面这几句相当重要了,是用xml文件实现dao接口的核心代码,因为数据库相关的大量工作我之前都写过了,所以这个看起来代码量很少
* 我也不太懂下面这个东西,我查API查了相当久,一开始写总是错,因为我理解错了InvocationHandler接口下那个方法的Object数组参数
* 它应该理解为一个可变长数组,而不是必须为数组
*/
Object instanze
= Proxy.newProxyInstance(classLoader, new Class[]{interfaze}, new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
List
list = mapper.getList();
Object obj
= null;
for(Function f:list)
{
if(f.getFuncName().equals(method.getName()))
{
/**
* 判断是不是select语句,是则调用DateUtil的select方法
* 否则调用update的方法
*/
if(f.getSqltype().equals("select"))
{
if("java.util.ArrayList".equals(f.getResultType()))
{
if(f.isParameter())
obj
= DataUtil.selectForBeanList(Class.forName(f.getResultOf()), f.getSql(), args);
else obj = DataUtil.selectForBeanList(Class.forName(f.getResultOf()), f.getSql());
}
else
{
if(f.isParameter())
obj
= DataUtil.selectForBean(Class.forName(f.getResultType()), f.getSql(), args);
else obj = DataUtil.selectForBean(Class.forName(f.getResultType()), f.getSql());
}
}

else
{
if(f.isParameter())
obj
= DataUtil.updata(f.getSql(), args);
else obj = DataUtil.updata(f.getSql());
}
}
}
return obj;
}
});
return instanze;
//返回这个接口,即mapper.getInterfaceName()这个接口

}

/**
* 读取xml文件的信息
*
@param path
*
@return
*/
private static MapperBean readMapper(String path)
{
File file
= new File(path);
SAXReader reader
= new SAXReader();
MapperBean mapper
= new MapperBean();
try
{
Document doc
= reader.read(file);
Element root
= doc.getRootElement(); //读取根节点 即dao节点
mapper.setInterfaceName(root.attributeValue("class").trim()); //把dao节点的class值存为接口名
mapper.setProxyName(root.attributeValue("id").trim()); //把id值设为代理名
List list = new ArrayList(); //用来存储方法的List
for(Iterator rootIter = root.elementIterator();rootIter.hasNext();) //遍历根节点下所有子节点
{
Function fun
= new Function(); //用来存储一条方法的信息
Element e = (Element) rootIter.next();
String sqltype
= e.getName().trim();
String funcName
= e.attributeValue("id").trim();
String sql
= e.getText().trim();
String resultType
= e.attributeValue("resultType").trim();
String resultOf
= "";
if("java.util.ArrayList".equals(resultType))
resultOf
= e.attributeValue("resultOf").trim();
String parameter
= e.attributeValue("parameter");
fun.setSqltype(sqltype);
fun.setFuncName(funcName);
fun.setResultType(resultType);
fun.setSql(sql);
fun.setResultOf(resultOf);
fun.setParameter(
"true".equals(parameter));
list.add(fun);
}
mapper.setList(list);

}
catch (DocumentException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return mapper;
}

下面写ServiceFactory我自己写了个注解


package com.yck.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SelfInject
{
String value();
}

在Service类中使用了这个注解


package com.yck.service;
import com.yck.annotation.SelfInject;
import com.yck.bean.User;
import com.yck.dao.IUserDao;
public class UserService
{
@SelfInject(value
="userdao")
private IUserDao userdao;

public User find(Integer id)
{
return userdao.selectById(id);
}
}

下面是ServiceFactory,先贴配置文件


xml version="1.0" encoding="UTF-8"?>
<services>
<service id="userService" class="com.yck.service.UserService"/>
services>

 


package com.yck.yebatis;
import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.yck.annotation.SelfInject;
import com.yck.bean.ServiceBean;
public class ServiceFactory implements BeanFactory
{
private static DaoFactory daoFactory = new DaoFactory();
private static Map beans;

static
{
configService();
}

/**
* 暴露获取方法
*/
@Override
public Object getBean(String beanName)
{
return beans.get(beanName);
}
/**
* 静态初始化方法
*/
private static void configService()
{
Map
map = new HashMap();
List
list= getServiceBeans();
for(ServiceBean service:list)
{
map.put(service.getProxyName(), implService(service));
}
beans
= map;
}

/**
* 读取所有的Service配置
*
@return
*/
private static List getServiceBeans()
{
SAXReader reader
= new SAXReader();
List
list = new ArrayList();
try
{
Document doc
= reader.read(new File("src/service/service.xml"));
Element root
= doc.getRootElement();
for(Iterator iter = root.elementIterator("service");iter.hasNext();)
{
Element e
= (Element) iter.next();
String proxyName
= e.attributeValue("id");
String className
= e.attributeValue("class");
ServiceBean bean
= new ServiceBean(proxyName, className);
list.add(bean);

}
}
catch (DocumentException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return list;

}


/**
* 实例化Service并注入所需依赖
*
@param service
*
@return
*/
public static Object implService(ServiceBean service)
{
Object obj
= null;
try
{
obj
= Class.forName(service.getClassName()).newInstance();
Class
c = obj.getClass();
Field[] fields
= c.getDeclaredFields();
for(Field f:fields)
{
Annotation[] annotations
= f.getAnnotations();
for(Annotation a:annotations)
{
if(a instanceof SelfInject)
{
Object o
= daoFactory.getBean(((SelfInject) a).value());
try
{
f.setAccessible(
true);
f.set(obj,o);
f.setAccessible(
false);
}
catch (IllegalArgumentException | IllegalAccessException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

}
catch (ClassNotFoundException | InstantiationException | IllegalAccessException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return obj;
}
}

最后测试有没有注入


package com.yck.test;
import com.yck.bean.User;
import com.yck.dao.IUserDao;
import com.yck.service.UserService;
import com.yck.yebatis.DaoFactory;
import com.yck.yebatis.ServiceFactory;
public class Test2
{

public static void main(String[] args)
{
DaoFactory bf
= new DaoFactory();
IUserDao userdao
= (IUserDao) bf.getBean("userdao");
User u
= userdao.selectById(2);
System.out.println(u);

ServiceFactory sf
= new ServiceFactory();
UserService userService
= (UserService) sf.getBean("userService");
User us
= userService.find(2);

System.out.println(us);


}
}

技术分享

最后查出结果,说明已经通过注解注入了

 

 

以上内容都是原创,如果转载请标注并标明来源于

大王让我写代码:http://www.cnblogs.com/yeyeck/p/7468644.html

 


推荐阅读
  • Web开发框架概览:Java与JavaScript技术及框架综述
    Web开发涉及服务器端和客户端的协同工作。在服务器端,Java是一种优秀的编程语言,适用于构建各种功能模块,如通过Servlet实现特定服务。客户端则主要依赖HTML进行内容展示,同时借助JavaScript增强交互性和动态效果。此外,现代Web开发还广泛使用各种框架和库,如Spring Boot、React和Vue.js,以提高开发效率和应用性能。 ... [详细]
  • 本文将带你快速了解 SpringMVC 框架的基本使用方法,通过实现一个简单的 Controller 并在浏览器中访问,展示 SpringMVC 的强大与简便。 ... [详细]
  • 深入解析Struts、Spring与Hibernate三大框架的面试要点与技巧 ... [详细]
  • Cookie学习小结
    Cookie学习小结 ... [详细]
  • 本文节选自《NLTK基础教程——用NLTK和Python库构建机器学习应用》一书的第1章第1.2节,作者Nitin Hardeniya。本文将带领读者快速了解Python的基础知识,为后续的机器学习应用打下坚实的基础。 ... [详细]
  • Spring 中 Bean 信息定义的三种方法探讨
    本文详细探讨了 Spring 框架中实现 Bean 信息定义的三种方法:基于 XML 配置、基于注解配置和基于 Java 类配置。每种方法都有其适用场景和优缺点。 ... [详细]
  • Spring – Bean Life Cycle
    Spring – Bean Life Cycle ... [详细]
  • 技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统
    技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统 ... [详细]
  • 优化后的标题:深入探讨网关安全:将微服务升级为OAuth2资源服务器的最佳实践
    本文深入探讨了如何将微服务升级为OAuth2资源服务器,以订单服务为例,详细介绍了在POM文件中添加 `spring-cloud-starter-oauth2` 依赖,并配置Spring Security以实现对微服务的保护。通过这一过程,不仅增强了系统的安全性,还提高了资源访问的可控性和灵活性。文章还讨论了最佳实践,包括如何配置OAuth2客户端和资源服务器,以及如何处理常见的安全问题和错误。 ... [详细]
  • 在Java Web服务开发中,Apache CXF 和 Axis2 是两个广泛使用的框架。CXF 由于其与 Spring 框架的无缝集成能力,以及更简便的部署方式,成为了许多开发者的首选。本文将详细介绍如何使用 CXF 框架进行 Web 服务的开发,包括环境搭建、服务发布和客户端调用等关键步骤,为开发者提供一个全面的实践指南。 ... [详细]
  • 事件是程序各部分之间的一种通信方式,也是异步编程的一种实现形式。本文将详细介绍EventTarget接口及其相关方法,以及如何使用监听函数处理事件。 ... [详细]
  • 本文详细介绍了Java代码分层的基本概念和常见分层模式,特别是MVC模式。同时探讨了不同项目需求下的分层策略,帮助读者更好地理解和应用Java分层思想。 ... [详细]
  • 本教程详细介绍了如何使用 Spring Boot 创建一个简单的 Hello World 应用程序。适合初学者快速上手。 ... [详细]
  • 基于Net Core 3.0与Web API的前后端分离开发:Vue.js在前端的应用
    本文介绍了如何使用Net Core 3.0和Web API进行前后端分离开发,并重点探讨了Vue.js在前端的应用。后端采用MySQL数据库和EF Core框架进行数据操作,开发环境为Windows 10和Visual Studio 2019,MySQL服务器版本为8.0.16。文章详细描述了API项目的创建过程、启动步骤以及必要的插件安装,为开发者提供了一套完整的开发指南。 ... [详细]
  • 本文详细探讨了几种常用的Java后端开发框架组合及其具体应用场景。通过对比分析Spring Boot、MyBatis、Hibernate等框架的特点和优势,结合实际项目需求,为开发者提供了选择合适框架组合的参考依据。同时,文章还介绍了这些框架在微服务架构中的应用,帮助读者更好地理解和运用这些技术。 ... [详细]
author-avatar
冬瓜
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有