自己实现IoC,AOP容器

自己实现IoC,AOP容器

 

Mini-Container 开发者手册

(Mini-Container Beta 0.9,
下载地址:http://www.blogjava.net/Files/chaocai/mini-container-beta-0.9.rar
)

蔡超

软件架构师

软件架构咨询顾问

[email protected]


Mini-Container是本人实现的一个轻量级的IoCInversion of Control, 控制反制)容器,并且提供了对AOP的简单支持。

IoC容器目前已经在各种项目中的得到了广泛的应用,它的使用大大提升了应用的可维护性和可测试性,并且简化的了应用的构建。在作者所参与的项目中这样的容器也无处不在。

为了加深对这些容器原理的理解,本人开发了这个容器,在开发过程中的确在很多方面都有了新的认识,如果不是亲自做过很多思想是很难体会的。

特将此容器的实现贡献给大家研究和学习,一同进步,一同分享,为振兴中国的软件业一同努力。

为在”5.12 特大地震中的受难同胞祈福,愿祖国更强大!


目录

Mini-Container特性

核心技术

从一个简单的示例开始

基本操作

组件(Component)及服务(Service

组件间的依赖

属性值的注入

简单AOP

整合Spring


 

Mini-Container特性

Mini-Container是一个轻量级的IoCInversion of Control, 控制反制)容器,并且提供了对AOP的简单支持。

Mini-Contaiiner具有以下特性:

1 轻量级的IoC容器,Mini-Container目前的版本使用和部署都十分简单,仅一个jar文件,mini-container.jar,

2 简单AOP支持,可以对组件提供的服务方法进行拦截, 加入自定义拦截器。

3 SOA in JVM,将SOA的思想融入其中,每个组件(component)声名自己可以提供的服务(service),这种服务通过Java interface进行定义及描述。各组件同时声明运行时所需依赖的服务(reference),容器会根据配置自动为该组件连接所需服务的提供者。

4 支持与其他Framework的整合,目前mini-container可以与spring进行整合。

运行环境要求JDK1.5以上。

核心技术

从一个简单的示例开始

以下示例展示了一个计算器服务的实现。

自己实现IoC,AOP容器_第1张图片
Mini-container的组件配置文件:calculator.xml

<?xml version="1.0" encoding="UTF-8"?>

<composite xmlns="http://www.ccsoft.org/schema/components" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

           xsi:schemaLocation="http://www.ccsoft.org/schema/components mini-container.xsd">

    <component name="CalculatorService" class="org.ccsoft.minicontainer.samples.calculator.impl.CalculatorServiceImpl">

       <service interface="org.ccsoft.minicontainer.samples.calculator.CalculatorService"/>

       <reference interface="org.ccsoft.minicontainer.samples.calculator.AddService" bind-property="addService"/>

       <reference interface="org.ccsoft.minicontainer.samples.calculator.SubtractService" bind-property="subtractService"/> 

       <reference interface="org.ccsoft.minicontainer.samples.calculator.MultiplyService" bind-property="multiplyService" />

       <reference interface="org.ccsoft.minicontainer.samples.calculator.DivideService" bind-property="divideService" />  

    </component>

    <component name="AddService" class="org.ccsoft.minicontainer.samples.calculator.impl.AddServiceImpl">

       <service interface="org.ccsoft.minicontainer.samples.calculator.AddService"/>      

    </component>

    <component name="SubtractService" class="org.ccsoft.minicontainer.samples.calculator.impl.SubtractServiceImpl">

        <service interface="org.ccsoft.minicontainer.samples.calculator.SubtractService"/>    

    </component>

    <component name="MultiplyService" class="org.ccsoft.minicontainer.samples.calculator.impl.MultiplyServiceImpl">

       <service interface="org.ccsoft.minicontainer.samples.calculator.MultiplyService"/>    

    </component>

    <component name="DivideService" class="org.ccsoft.minicontainer.samples.calculator.impl.DivideServiceImpl">

       <service interface="org.ccsoft.minicontainer.samples.calculator.DivideService"/>   

    </component>

</composite>

可见配置文件,清晰的表达了这种组件与服务间的关系,实现代码参见CalculatorSample

基本操作

1 初始化一个Mini-Container

MiniContainer container=new MiniContainer();

              container.loadBundlesFromClassPath("first.xml");

2 获取可用组件

//获取服务上下文

ServiceContext context=container.getServiceContext();            

SaySomething service=(SaySomething) container.getServiceContext().getServiceByType(SaySomething.class.getName());

获取组件可以根据组件提供的服务及组件名来获取。

其它相关API

       /**

        * get the service instance by component name

        * @param name component name

        * @return

        */

       public Object getServiceByName(String name);

       /**

        * get the service instance by service type

        * @param type service type

        * @return

        */

       public Object getServiceByType(String type);

       /**

        * get the service instance by service type and component name

        * @param type service type

        * @param name component name

        * @return

        */

       public Object getServiceByType(String type,String name);

       /**

        * get the all the service instance by service type

        * @param type serviceType

        * @return

        */

3 获取未激活的组件

如果组件的依赖关系无法得到解决,则组件将处于未激活状态,未激活的组件可以通过以下方式获取:

Set<?> bundles=context.getUnResolvingServiceBundles();

组件(Component)及服务(Service

Mini-Container中所指的组件是通过普通的Java Bean实现的,通常情况组件会通过Java Interface定义组件所能提供的服务,并且通过Java Bean(组件的实现来实现这个接口)。

配置文件定义如下:

<?xml version="1.0" encoding="UTF-8"?>

<composite xmlns="http://www.ccsoft.org/schema/components" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

           xsi:schemaLocation="http://www.ccsoft.org/schema/components mini-container.xsd">

    <component name="AddService" class="org.ccsoft.minicontainer.samples.calculator.impl.AddServiceImpl">

       <service interface="org.ccsoft.minicontainer.samples.calculator.AddService"/>      

    </component>

</composite>

接口:AddService.java

package org.ccsoft.minicontainer.samples.calculator;

/**

 * The Add service interface

 */

public interface AddService {

    double add(double n1, double n2);

}

组件实现:AddServiceImpl.java

package org.ccsoft.minicontainer.samples.calculator.impl;

import org.ccsoft.minicontainer.samples.calculator.AddService;

/**

 * An implementation of the Add service

 */

public class AddServiceImpl implements AddService {

    public double add(double n1, double n2) {

        return n1 + n2;

    }

}

一个组件可以实现多个接口,从而暴露多个服务。

组件间的依赖

Mini-Container能够通过IoC帮助我们管理组件间的依赖。与Spring不同的是我们通常不需指明具体依赖的组件的名字,而是指明所依赖的服务(即java interface)。

<component name="CalculatorService" class="org.ccsoft.minicontainer.samples.calculator.impl.CalculatorServiceImpl">

       <service interface="org.ccsoft.minicontainer.samples.calculator.CalculatorService"/>

       <reference interface="org.ccsoft.minicontainer.samples.calculator.AddService" bind-property="addService"/>

       <reference interface="org.ccsoft.minicontainer.samples.calculator.SubtractService" bind-property="subtractService"/> 

       <reference interface="org.ccsoft.minicontainer.samples.calculator.MultiplyService" bind-property="multiplyService" />

       <reference interface="org.ccsoft.minicontainer.samples.calculator.DivideService" bind-property="divideService" />  

    </component>

通过referece元素指定组件所依赖的服务,及这种服务实现被注入后所绑定的属性名称(通过bind-property指定)。

当如果多个组件提供了某组件所依赖的服务时,容器会在其中自动选择一个进行关系注入。通过filter属性我们还可以在这种情况下指定具体的组件,filter属性值为所指定的组件名。

<reference interface="org.ccsoft.mc.samples.HelloService" bind-property="helloService" filter="sorryService"/>

Cardinality属性

通过将该属性设置为”1..n”,我们可以将多个服务提供者注入到依赖当中,但这是绑定的属性必须是集合类型。

<component name="helloServiceInvoker" class="org.ccsoft.mc.samples.HelloServiceInvoker">

       <service interface="org.ccsoft.mc.samples.HelloService"/>

       <reference interface="org.ccsoft.mc.samples.HelloService" bind-property="services" cardinality="1..n"/>

    </component>

package org.ccsoft.mc.samples;

import java.util.Collection;

public class HelloServiceInvoker implements HelloService{

       private Collection<HelloService> services;

       public String sayHello(String sb) {

              String ret="";

              for (HelloService service:services){

                     ret+=service.sayHello(sb)+""n";

              }

              return ret;

       }

       public Collection<HelloService> getServices() {

              return services;

       }

       public void setServices(Collection<HelloService> services) {

              this.services = services;

       }

}

属性值的注入

Mini-Container支持对组件实现类的特定属性通过配置文件进行值的注入,目前版本支持注入的类型包括,数据类型,字符类型及日期类型。

<component name="helloService" class="org.ccsoft.mc.samples.HelloServiceImpl">

       <service interface="org.ccsoft.mc.samples.HelloService"/>  

       <property name="greeting" value="Hi"/>

       <property name="date" value="2008-05-08 15:00:00"/>    

    </component>

public class HelloServiceImpl implements HelloService {

       private String greeting;

       private Date date;

       public String getGreeting() {

              return greeting;

       }

       public void setGreeting(String greeting) {

              this.greeting = greeting;

       }

       public String sayHello(String sb) {             

              return greeting+" "+sb+" "+date;

       }

       public Date getDate() {

              return date;

       }

       public void setDate(Date date) {

              this.date = date;

       }

}

注意目前日期支持的格式为:yyyy-MM-dd HH:mm:ss

简单AOP

Mini-Container支持了简单的AOP功能,可以对服务的调用进行拦截。这种拦截是通过实现和定义interceptor来实现的(与EJB3interceptor几乎一致)。

package org.ccsoft.mc.samples;

import org.ccsoft.mc.core.Interceptor;

import org.ccsoft.mc.core.InvocationContext;

public class HelloServiceInterceptor implements Interceptor {

       public HelloServiceInterceptor() {

              super();

              // TODO Auto-generated constructor stub

       }

       public Object invoke(InvocationContext ctx) throws Exception {

              System.out.println("before method:"+ctx.getMethod());

              //invoke the method

              Object ret=ctx.proceed();

              System.out.println("after method");

              //modify the result

              return (String)ret+"[exist interceptor]";

       }

}

配置如下

<component name="helloService" class="org.ccsoft.mc.samples.HelloServiceImpl">

       <service interface="org.ccsoft.mc.samples.HelloService">

         <interceptor class="org.ccsoft.mc.samples.HelloServiceInterceptor"/>         

       </service>   

       <property name="greeting" value="Hi"/>

       <property name="date" value="2008-05-08 15:00:00"/>    

    </component>

可以通过InvocationContext对象来激活被拦截的对象的方法,通过该对象还可以获得当前被拦截的方法的方法名及传入的参数。

整合Spring

Mini-container可以于Spring进行整合,从而获得更加完善和强大的功能,可以在spring中使用Mini-Container的组件。

配置示例:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xsi:schemaLocation="

http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

 

 <bean id="springSpeaker" class="org.ccsoft.mc.samples.support.spring.SaySometingSpringBeanImpl">

    <property name="speaker" ref="miniSpeaker"/>  

 </bean>

 <bean id="miniContainerBridge" class="org.ccsoft.mc.support.spring.MiniContainerBridge">

   <property name="configFile" value="first.xml"/>

 </bean>

 <bean id="miniSpeaker" class="org.ccsoft.mc.support.spring.MiniContainerComponentFactory">

    <property name="service" value="org.ccsoft.mc.samples.SaySomething"/>

   <property name="context" ref="miniContainerBridge"/>

 </bean>

</beans>

            

说明:

1 spring的配置加入beanorg.ccsoft.mc.support.spring.MiniContainerBridge,并通过其configFile属性指明Mini-Container的配置文件

2通过bean: org.ccsoft.mc.support.spring.MiniContainerComponentFactory获取Mini-Container中注册的服务。

Propertyservice,指明要引入的服务

Propertycontext,引用org.ccsoft.mc.support.spring.MiniContainerBridge

Propertyfilter,本示例中未给出,指定mini-container中组件名称,用于过滤服务提供组件。

下载地址:
http://www.blogjava.net/Files/chaocai/mini-container-beta-0.9.rar
在找到合适的站点后我会Open-Source.

你可能感兴趣的:(自己实现IoC,AOP容器)