详解JavaSE实现IoC

JavaSE中的IoC实现方式

Java SE 提供了三种方式,可以实现IoC,分别为:

  • Java Beans
  • Java ServiceLoader SPI
  • JNDI(Java Naming and Directory Interface)

Java Beans

java.beans包下的 Introspector 类提供了一个 getBeanInfo的方法,可以获取一个类的信息

BeanInfo bi = Introspector.getBeanInfo(User.class,Object.class);

如上,则可以获取User类对象的BeanInfo, 然后我们通过BeanInfo中的 getPropertyDescriptors 方法,可以获取到User对象中的所有属性和方法,

注意:java beans中,对于set(xxx)方法,统一叫:writeMethod(), 对于get() 方法,统一叫:readMethod()

Stream.of(bi.getPropertyDescriptors()).forEach(pd->{
        Class<?> propertyType=pd.getPropertyType();
        Method writeMethod=pd.getWriteMethod();
        });

获取到方法和属性名称后,通过反射即可把对应的值设置到对应的属性中

writeMethod.invoke(name,value);

由于我们注入属性值的时候,我们注入的东西永远是一个字符串类型,如果需要注入的属性是其他类型(非字符串), 比如User类中,有一个属性是address,这个address是一个对象类型,我们应该如何定义一个转换器,将字符串类型的值转换为我们需要的对象类型呢?

我们需要通过设置一个AddressEditor来实现这个转换,这个AddressEditor有如下两种实现方式:

实现PropertyEditor接口

继承PropertyEditorSupport类,重写setAsText方法

PropertyEditorSupport类提供了一些比较便利的实现方式,所以我们采用继承PropertyEditorSupport类的方法,来实现类型的转换,

Address类的设计是:

public class Address {
    private String name;
    private Integer num;
    // 省略 get / set / toString
}

我们的定义的规则如下,

输入的字符串用|来分割 name 和 num属性

例如: “贝克街|221” 这个字符串 会将“贝克街”赋给name,221赋给num,所以,我们重写setAsText方法的逻辑如下:

public class AddressEditor extends PropertyEditorSupport {
    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        String[] tokens = text.split("\\|");
        Address address = new Address();
        address.setName(tokens[0]);
        address.setNum(Integer.valueOf(tokens[1]));
        setValue(address);
    }
}

同理,我们可以实现一个DateEditor,让“yyyy-MM-dd”这样类型的字符串转换成日期格式。

public class DateEditor extends PropertyEditorSupport {

    static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        LocalDate localDate = LocalDate.parse(text, dtf);
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();
        setValue(Date.from(instant));
    }
}

然后,我们需要使用java beans中的PropertyEditorManager类的registerEditor方法把这两个Editor注册进来

registerEditor(Address.class,AddressEditor.class);
registerEditor(Date.class,DateEditor.class);

最后,PropertyEditorManager的findEditor方法就可以根据我们前面得到的属性类型,找到对应的Editor来对值进行转换,转换成我们需要的属性类型的值

PropertyEditor editor=findEditor(propertyType);
if(editor!=null){
    // 这一步就是为所有属性找到其对应的解析器
    editor.setAsText(parameters.get(pd.getName()));
    try{
        writeMethod.invoke(user,editor.getValue());
    }catch(IllegalAccessException|InvocationTargetException e){
        e.printStackTrace();
    }
}else{
    System.out.println("no editor for:"+pd.getName());
}

主函数调用示例

public static void main(String[]args)throws Exception{
    Map<String, String> parameters=new HashMap<String, String>(){
        {
            //这里的key要和Node里面的属性名一致
            put("name","福尔摩斯");
            put("address","贝克街|221");
            put("birthday","1854-01-06");
        }
    };
    User convert=PropertyEditorSample.convert(parameters);
    System.out.println(convert);
}

运行结果

User{name='福尔摩斯', birthday=Thu Jan 05 23:54:17 CST 1854, address=Address{name='贝克街, 221 号}}

SPI

定义支付接口PayService

public interface PayService {
    void pay();
}

定义多个实现:

public class WeixinpayService implements PayService {
    @Override
    public void pay() {
        System.out.println("微信支付");
    }
}
public class AlipayService implements PayService {
    @Override
    public void pay() {
        System.out.println("支付宝支付");
    }
}

在resources目录下建立META-INF文件夹,在META-INF文件夹下建立services目录,同时建立一个文件,名称为接口的全路径名,以这个项目为例, PayService的全路径名称为:

org.snippets.ioc.java.spi.PayService

在这个文件内,把实现类的全路径名写进去:

org.snippets.ioc.java.spi.AlipayService
org.snippets.ioc.java.spi.WeixinpayService

客户端调用:

ServiceLoader<PayService> serviceLoader=ServiceLoader.load(PayService.class);

for(PayService ele:serviceLoader){
    ele.pay();
}

其中ServiceLoader.load方法可以把所有配置的PayService实现得到

执行结果:

支付宝支付

微信支付

JNDI方式

定义一个Person类

public class Person implements Remote, Serializable {

    private static final long serialVersionUID = 1L;
    private String name;
    private String password;

    // 省略set / get方法
}

实现JNDI的客户端,实现初始化Person和查找Person两个功能

public static void initPerson()throws Exception{
    //配置JNDI工厂和JNDI的url和端口。如果没有配置这些信息,将会出现NoInitialContextException异常
    LocateRegistry.createRegistry(3000);
    System.setProperty(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.rmi.registry.RegistryContextFactory");
    System.setProperty(Context.PROVIDER_URL,"rmi://localhost:3000");

    InitialContext ctx=new InitialContext();

    //实例化person对象
    Person p=new Person();
    p.setName("zc");
    p.setPassword("123");

    //将person对象绑定到JNDI服务中,JNDI的名字叫做:person。
    ctx.bind("person",p);
    ctx.close();
}

public static void findPerson()throws Exception{
    //因为前面已经将JNDI工厂和JNDI的url和端口已经添加到System对象中,这里就不用在绑定了
    InitialContext ctx=new InitialContext();

    //通过lookup查找person对象
    Person person=(Person)ctx.lookup("person");

    //打印出这个对象
    System.out.println(person.toString());
    ctx.close();
}

以上就是详解JavaSE实现IoC的详细内容,更多关于JavaSE实现IoC的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java基础之Spring5的核心之一IOC容器

    一.什么是IOC 1)控制反转,把创建对象和对象的调用过程交给Spring 管理. 2)使用IOC的目的,为了降低耦合度. 二.IOC的底层原理 XML解析.工厂模式.反射 三.IOC思想 基于IOC容器完成,IOC容器底层就是对象工厂. 四.Spring 提供IOC容器实现两种方式:(两个接口) (1)BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员使用 特点:加载配置文件的时候不会创建对象,在获取(使用)对象才去创建. (2)ApplicationCo

  • 轻松理解Java面试和开发中的IoC(控制反转)

    IoC的概念介绍 控制反转(IOC)模式(又称DI:Dependency Injection)就是Inversion of Control,控制反转.在Java开发中,IoC意 味着将你设计好的类交给系统去控制,而不是在你的类内部控制.这称为控制反转. 控制反转(Inversion of Control,英文缩写为IoC)是框架的重要特征,做到控制反转需要一个容器来实现,就是我们所说的IoC容器,最常见的IoC容器是Spring. 控制反转从字面意思看来不是很好理解,其实就是将创建管理对象的工作

  • 用java的spring实现一个简单的IOC容器示例代码

    要想深入的理解IOC的技术原理,没有什么能比的上我们自己实现它.这次我们一起实现一个简单IOC容器.让大家更容易理解Spring IOC的基本原理. 这里会涉及到一些java反射的知识,如果有不了解的,可以自己去找些资料看看. 注意 在上一篇文章,我说,启动IOC容器时,Spring会将xml文件里面配置的bean扫描并实例化,其实这种说法不太准确,所以我在这里更正一下,xml文件里面配置的非单利模式的bean,会在第一次调用的时候被初始化,而不是启动容器的时候初始化.但是我们这次要做的例子是容

  • 基于Java反射技术实现简单IOC容器

    前言 首先思考一个问题,如果你正在做一个复杂的系统,一个系统模块内有几百个功能业务类,这些类需要使用同一些对象来进行工作.那么,你会怎样去管理这些通用且一样的对象呢? 学习过Spring的朋友会知道,Spring框架为此提供了一种非常先进的思想,即IOC(控制反转).Spring可以理解为一个工厂,负责对象的创建和对象间关系的维护.IoC即控制反转,简单说就是之前需要使用new的方式创建对象,而Spring框架会从XML文件中根据配置的信息来创建对象,然后放进它自己的容器之中.在程序要使用到该对

  • 使用Java注解模拟spring ioc容器过程解析

    使用注解,简单模拟spring ioc容器.通过注解给对象属性注入值. 项目结构 annotation 包,用于存放自定义注解 Component 注解表示该类为组件类,并需要声明名字 package priv.haidnor.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy;

  • 深入理解java的spring-ioc的使用

    spring-ioc的使用 IOC容器在很多框架里都在使用,而在spring里它被应用的最大广泛,在框架层面上,很多功能都使用了ioc技术,下面我们看一下ioc的使用方法. 把服务注册到ioc容器 使用属性注入反射对应类型的实例 多态情况下,使用名称反射类型的实例 把服务注册到ioc容器 @Bean注册组件 使用@Bean注解进行类型的注册,默认你的ioc容器里类型为bean的返回值,名称为bean所有的方法名,与你的包名称没有直接关系,如果你的接口有多种实现,在注册时可以使用@Bean("li

  • Java使用IOC控制反转的三种设计模式详解

    对于许多开发人员来说,控制反演(IoC)都是一个模糊的概念,因为他们在现实世界中很少或没有被应用过.在最好的情况下,控制反演(IoC)可以加单的认为是等效于依赖注入(DI).实际上,只有在翻转控制与依赖注入双方都只是反映翻转依赖管理控制的时候,才认为两者是等效的.虽然,依赖注入实际上是IoC的一种众所周知的形式.但是,事实上IoC却是一个相对更为广泛的软件设计范例,可以通过多种模式来进行实现.在本文中,我们将介绍依赖注入,观察者模式和模板方法模式如何实现控制反转的. 正如许多其他设计模式,是从各

  • Spring学习笔记1之IOC详解尽量使用注解以及java代码

    在实战中学习Spring,本系列的最终目的是完成一个实现用户注册登录功能的项目. 预想的基本流程如下: 1.用户网站注册,填写用户名.密码.email.手机号信息,后台存入数据库后返回ok.(学习IOC,mybatis,SpringMVC的基础知识,表单数据验证,文件上传等) 2.服务器异步发送邮件给注册用户.(学习消息队列) 3.用户登录.(学习缓存.Spring Security) 4.其他. 边学习边总结,不定时更新.项目环境为Intellij + Spring4. 一.准备工作. 1.m

  • Java开发到底为什么要用 IoC 和 AOP

    作为一名 Java 开发,对 Spring 框架是再熟悉不过的了.Spring 支持的控制反转(Inversion of Control,缩写为IoC)和面向切面编程(Aspect-oriented programming,缩写为AOP)早已成为我们的开发习惯,仿佛 Java 开发天生就该如此.人总是会忽略习以为常的事物,所有人都熟练使用 IoC 和 AOP,却鲜有人说得清楚到底为什么要用 IoC 和 AOP. 技术肯定是为了解决某个问题而诞生,要弄清楚为什么使用 IoC 和 AOP,就得先弄清

  • 详解JavaSE实现IoC

    JavaSE中的IoC实现方式 Java SE 提供了三种方式,可以实现IoC,分别为: Java Beans Java ServiceLoader SPI JNDI(Java Naming and Directory Interface) Java Beans java.beans包下的 Introspector 类提供了一个 getBeanInfo的方法,可以获取一个类的信息 BeanInfo bi = Introspector.getBeanInfo(User.class,Object.c

  • 详解JavaSE中抽象类与接口的定义及使用

    目录 一.抽象类 1.抽象类定义 2.抽象方法 二.接口 1.接口定义 2.类实现接口 3.接口与多态联合 4.extends和implements 5.接口在开发当中的作用 6.is has like 7.抽象类与接口 一.抽象类 1.抽象类定义 1.什么是抽象类? 类和类之间具有共同特征,将这些共同特征提取出来,形成的就是抽象类. 类到对象是实例化,对象到类是抽象. 抽象类无法实例化,无法创建对象.抽象类是类和类之间有共同特征,将这些具有共同特征的类再进一步抽象,就形成了抽象类.由于类本身是

  • 详解Spring框架---IOC装配Bean

    IOC装配Bean (1)Spring框架Bean实例化的方式提供了三种方式实例化Bean 构造方法实例化(默认无参数,用的最多) 静态工厂实例化 实例工厂实例化 下面先写这三种方法的applicationContext.xml配置文件: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"

  • spring实现bean对象创建代码详解

    我以一个简单的示例解构spring是怎样管理java对象的. 首先,定义一个简单的pojo,代码如下: package com.jvk.ken.spring; public class Demo { private String name; public Demo() { name="I'm Demo."; } public void printName() { System.out.println(name); } public void setName(String name) {

  • spring的IoC和DI详解

    这里先来简单介绍下IoC和DI的区别: IOC:翻译过来是控制反转,将对象的创建权由Spring管理,HelloService不需要自己去创建,Spring可以帮你创建. DI:依赖注入,在我们创建对象的过程中,把对象依赖的属性注入到我们的类中. 我们现在编写的类是没有其它的属性的,如果你学过UML这种设计的话,面向对象中对象中的几种关系 简单来书,IoC更像是一种思想,DI是一种行为. 另一种说法是,ioc是目的,di是手段.ioc是指让生成类的方式由传统方式(new)反过来,既程序员不调用n

  • Spring IOC原理详解

    最近,买了本Spring入门书:springInAction.大致浏览了下感觉还不错.就是入门了点.Manning的书还是不错的,我虽然不像哪些只看Manning书的人那样专注于Manning,但怀着崇敬的心情和激情通览了一遍.又一次接受了IOC.DI.AOP等Spring核心概念.先就IOC和DI谈一点我的看法. IOC(DI):其实这个Spring架构核心的概念没有这么复杂,更不像有些书上描述的那样晦涩.java程序员都知道:java程序中的每个业务逻辑至少需要两个或以上的对象来协作完成,通

  • 简单实现Spring的IOC原理详解

    控制反转(InversionofControl,缩写为IoC) 简单来说就是当自己需要一个对象的时候不需要自己手动去new一个,而是由其他容器来帮你提供:Spring里面就是IOC容器. 例如: 在Spring里面经常需要在Service这个装配一个Dao,一般是使用@Autowired注解:类似如下 public Class ServiceImpl{ @Autowired Dao dao; public void getData(){ dao.getData(); } 在这里未初始化Dao直接

  • spring在IoC容器中装配Bean详解

    1.Spring配置概述 1.1.概述 Spring容器从xml配置.java注解.spring注解中读取bean配置信息,形成bean定义注册表: 根据bean定义注册表实例化bean: 将bean实例放入bean缓存池: 应用程序使用bean. 1.2.基于xml的配置 (1)xml文件概述 xmlns------默认命名空间 xmlns:xsi-------标准命名空间,用于指定自定义命名空间的schema文件 xmlns:xxx="aaaaa"-------自定义命名空间,xx

  • Spring IOC和aop的原理及实例详解

    这篇文章主要介绍了Spring IOC和aop的原理及实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架.特点是面向接口编程,松耦合. 1:IOC(控制反转) 别名(DI:依赖注入) 首先来一段ioc的实现原来代码: public class ClassPathXmlApplicationContext implements BeanFactory { privat

随机推荐