java json injection_Java Web实现IOC控制反转之依赖注入

控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机程序的耦合问题,也是轻量级的Spring框架的核心。

控制反转一般分为两种类型,依赖注入(Dependency Injection,简称DI)和依赖查找(Dependency Lookup)。

依赖注入应用比较广泛。本文介绍java实现一个简单的依赖注入

简单而言,当你在某一个类中需要调用其他的类并且生成对象,大部分情况是new一个对象,此时如果你不确定要new哪一个对象,你就需要为所有的类作if或者switch判断,在不同情况下new不同的对象,然后给他们属性赋值

使用最多的地方就是JavaBean类和他们的对象了,假设项目的Model里面有Teacher,StudentClass,分别代表老师和班级两个javaBean类

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

public classTeacher {privateString name;privateString id;publicString getName() {returnname;

}public voidsetName(String name) {this.name =name;

}publicString getId() {returnid;

}public voidsetId(String id) {this.id =id;

}

@OverridepublicString toString() {return "Teacher [name=" + name + ", id=" + id + "]";

}

}

Teacher.java

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

public classSchoolClass {privateString schoolClassName;privateString schoolClassId;privateTeacher manager;publicString getSchoolClassName() {returnschoolClassName;

}public voidsetSchoolClassName(String schoolClassName) {this.schoolClassName =schoolClassName;

}publicString getSchoolClassId() {returnschoolClassId;

}public voidsetSchoolClassId(String schoolClassId) {this.schoolClassId =schoolClassId;

}publicTeacher getManager() {returnmanager;

}public voidsetManager(Teacher manager) {this.manager =manager;

}

@OverridepublicString toString() {return "The manager of "+schoolClassName+"("+schoolClassId+")"+"is Teacher"+manager.toString();

}

SchoolClass

此时,我们有一个老师,两个班级,那么在实际使用中是不是就要new一个老师,然后使用getter,setter为他赋值属性,然后new两个班级,并且按照老师的做法赋值,这样如果有很多的老师和班级,那么就要不停的在java代码中new,new,new......

而且每次多一个老师,班级,我们就要修改java代码,重新编译,这样耦合度就很高,能不能使用一个工具类自动新建对象,而对象的信息保存在一个文本中

IoC的设计模式解决了这个问题,使用依赖注入,我们把类以及类相依赖的类放到动态修改的文本当中,每次从文本中读取,然后根据文本信息,动态的new出这些对象,做到灵活,多样化,易扩展。这样不在需要去修改或者添加java代码,代码重复性也减少。

看看设计图:

4ed857a8f81de296465cacaa764012db.png

开始,新建一个web dynamic项目

目录结构如下:

60655a5f3861e6cadacacf852c7e6db3.png

其中两个javaBean放在app包中,确切说这是pojo类

ioc包里面是ioc核心控制器

test包是一个servlet,主要用于Ioc是否成功的测试

由于个人觉得xml文件的书写和读取,传输都不是很好,尤其在spring,struts的配置均采用xml,实在厌恶

之前在做php开发的时候,配置文件一般是json的格式或者php对象的格式(好吧,两者只是本质有区别,事实上形式相似)

所以,我这次异想天开的在自己的IoC中使用Json作为依赖注入的动态配置文件取代大部分框架使用的xml文件

如下:

[

{"bean": "cn.cslg.app.Teacher","id": "class_manager","properties": {"name": "黄有为","id": "200500027"}

},

{"bean": "cn.cslg.app.SchoolClass","id": "class1","properties": {"schoolClassId": "Z094141","schoolClassName": "软件工程"},"ref": {"manager": "class_manager"}

},

{"bean": "cn.cslg.app.SchoolClass","id": "class2","properties": {"schoolClassId": "Z094142","schoolClassName": "软件工程"},"ref": {"manager": "class_manager"}

}

]

213c83133d6d4eee05fbca4f16abba7d.png

IocListener代码如下:

packagecn.cslg.ioc;importjavax.servlet.ServletContext;importjavax.servlet.ServletContextEvent;importjavax.servlet.ServletContextListener;importjavax.servlet.annotation.WebListener;

@WebListenerpublic class IocListener implementsServletContextListener{private final String filename = "/WEB-INF/ioc.json";

@Overridepublic voidcontextInitialized(ServletContextEvent sce) {//TODO Auto-generated method stub

ServletContext context =sce.getServletContext();

String configFile= context.getInitParameter("ioc-config");

String path=context.getRealPath(filename);try{if (configFile != null) {

path=context.getRealPath(configFile);

}

ConfigParser parser= newConfigParser(path);

context.setAttribute("APPLICATION_CONTEXT_BEANS", parser.parse());

}catch(IocException e) {//TODO: handle exception

e.printStackTrace();

}

}

@Overridepublic voidcontextDestroyed(ServletContextEvent sce) {//TODO Auto-generated method stub

}

}

实现对servlet上下文的监听,主要是调用了ConfigParser创建对象并在servlet中增加了一个值

APPLICATION_CONTEXT_BEANS

将刚刚创建的beans对象保存在其中,以便servlet使用过程中使用

ConfigParser实现了控制反转的依赖注入,类构成如下:

17de3a42d1bf1323487b0b72444f6fa1.png

类私有属性:

private HashMap beansMap = new HashMap<>();privateString jsonString;private String filename;

类构造方法:

publicConfigParser(String filename) {super();this.filename =filename;this.jsonString =ReadJsonFile(filename);

}

使用ReadJsonFile对json进行解析,返回json的字符串,交给jsonString

ReadJsonFile代码如下:

privateString ReadJsonFile(String path) {

File file= newFile(path);

BufferedReader reader= null;

String laststr= "";try{

reader= new BufferedReader(newFileReader(file));

String tempString= null;int line = 1;while ((tempString = reader.readLine()) != null) {

System.out.println("line " + line + ": " +tempString);

laststr= laststr +tempString;

line++;

}

reader.close();

}catch(IOException e) {

e.printStackTrace();

}finally{if (reader != null) {try{

reader.close();

}catch(IOException e1) {

}

}

}returnlaststr;

}

其中解析json(JsonArray,JsonObject)需要用到json-lib,javaBean是解析需要用到common-beanutils

请使用gradle或者手动导入这两个包,如使用gradle如下:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

repositories {

mavenCentral()

jcenter()

maven { url"http://repo.spring.io/release"}

}

dependencies {

compile group:'net.sf.json-lib', name: 'json-lib', version: '2.4'compile group:'commons-beanutils', name: 'commons-beanutils', version: '1.9.3'compile group:'javax.servlet', name: 'javax.servlet-api', version: '3.1.0'testImplementation'junit:junit:4.12'}

View Code

instance方法,第一步“创建对象”,class.forname和class.newInstance是核心,有了他们实现了类->对象的创建

public void instantiate() throwsIocException {

JSONArray beans=(JSONArray) JSONArray.fromObject(jsonString);try{for (Iterator it =beans.iterator(); it.hasNext();) {

JSONObject bean=(JSONObject) it.next();

String className= (String) bean.get("bean");

String idName= (String) bean.get("id");

Object obj;

Class> class1 =Class.forName(className);

obj=class1.newInstance();

beansMap.put(idName, obj);

}

}catch(Exception e) {//TODO Auto-generated catch block

e.printStackTrace();

}

}

injection方法,为instance创建的对象赋值属性,主要包括了普通值,引用值

public void injection() throwsIocException {

JSONArray beans=(JSONArray) JSONArray.fromObject(jsonString);try{for (Iterator it =beans.iterator(); it.hasNext();) {

JSONObject bean=(JSONObject) it.next();

String beanId= bean.get("id").toString();

Object beanObj=beansMap.get(beanId);if (beanObj != null) {

PropertyDescriptor pds[]=PropertyUtils.getPropertyDescriptors(beanObj);

JSONObject properties= (JSONObject) bean.get("properties");

JSONObject ref= (JSONObject) bean.get("ref");

Iterator keyIter;

String key;

String value;if (properties != null) {

keyIter=properties.keys();while(keyIter.hasNext()) {

key=(String) keyIter.next();for(PropertyDescriptor pd : pds) {if(pd.getName().equals(key)) {

value=properties.get(key).toString();if (value != null)

pd.getWriteMethod().invoke(beanObj, (Object) value);

}

}

}

}if (ref != null) {

keyIter =ref.keys();while(keyIter.hasNext()) {

key=keyIter.next().toString();for(PropertyDescriptor pd : pds) {if(pd.getName().equals(key)) {

value=ref.get(key).toString();if (value != null)

pd.getWriteMethod().invoke(beanObj, beansMap.get(value));

}

}

}

}

}

}

}catch(Exception e) {

e.printStackTrace();

}

}

注意在json中,配置了对象的赋值,properties是普通的属性值,可以int,String值。而ref则是引用值,引用了其他的对象,这里是Teacher对象,表示班级由某一个老师管理。注意处理时要区别对待

其中使用了两重循环迭代,第一重遍历bean对象是数组JsonArray,第二重遍历bean下的properties或者是ref是对象JsonObject,从json文件中不难看出其迭代结构

核心方法是invoke,替代了getter,setter,直接对对象的属性进行赋值(初始化),值从json文件的properties和ref中获取,并且一一对应的赋值

注意java中,json对象是不能直接转化为JavaBean对象的,需要对其一层层遍历手动赋值,php则可以直接将json转化为对象,因为php本身是动态语言!

最后,parse方法返回一个HashMap,存储了所有生成的JavaBean对象:

public HashMap parse() throwsIocException {

instantiate();

injection();returnbeansMap;

}

使用,servlet进行测试:

TestIocServlet.java的代码:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

@WebServlet("/TestIocServlet")public class TestIocServlet extendsHttpServlet {private static final long serialVersionUID = 1L;

@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {

resp.setCharacterEncoding("utf-8");

resp.setContentType("text/html");try (PrintWriter out =resp.getWriter()) {

@SuppressWarnings("unchecked")

HashMap beans = (HashMap) this.getServletContext()

.getAttribute("APPLICATION_CONTEXT_BEANS");

Set keys =beans.keySet();for(String key : keys) {

out.println(key+ ": " + beans.get(key) + "
");

}

}

}

}

View Code

启动tomcat运行servlet,浏览器效果如下:

6bd070ffa58f8c98d785c192ee172cd2.png

很明显,已经实现了对文本json文件的动态对象生成和赋值,不需要在java文件中重复new对象并且赋值

对了,项目中有个异常处理文件,IocException.java如下:

public class IocException extendsException{publicIocException(Throwable cause){super(cause);

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值