Apache Mina 与 Aries 蓝图的集成有问题

Apache Mina Integration With Aries blueprint have problem

https://mina.apache.org/mina-project/userguide/ch17-spring-integration/ch17-spring-integration.html

link 的用户指南,它适用于所有 DI 框架。

但是通过Aries蓝图注入时出现如下错误,未初始化

        2022-02-09T11:59:53,554 | ERROR | Blueprint Extender: 3 | BlueprintContainerImpl | 60 - org.apache.aries.blueprint.core - 1.10.3 | Unable to start container for blueprint bundle io-bridge/0.0.1.SNAPSHOT
            org.osgi.service.blueprint.container.ComponentDefinitionException: Error setting property: PropertyDescriptor <name: filters, getter: null, setter: [class org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder.setFilters(interface java.util.Map)]
                at org.apache.aries.blueprint.container.BeanRecipe.setProperty(BeanRecipe.java:818) ~[!/:1.10.3]
                at org.apache.aries.blueprint.container.BeanRecipe.setProperties(BeanRecipe.java:784) ~[!/:1.10.3]
                at org.apache.aries.blueprint.container.BeanRecipe.setProperties(BeanRecipe.java:765) ~[!/:1.10.3]
                at org.apache.aries.blueprint.container.BeanRecipe.internalCreate2(BeanRecipe.java:699) ~[!/:1.10.3]
                at org.apache.aries.blueprint.container.BeanRecipe.internalCreate(BeanRecipe.java:666) ~[!/:1.10.3]
                at org.apache.aries.blueprint.di.AbstractRecipe.call(AbstractRecipe.java:81) ~[!/:1.10.3]
                at java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[?:?]
                at org.apache.aries.blueprint.di.AbstractRecipe.create(AbstractRecipe.java:90) ~[!/:1.10.3]
                at org.apache.aries.blueprint.di.RefRecipe.internalCreate(RefRecipe.java:62) ~[!/:1.10.3]
                at org.apache.aries.blueprint.di.AbstractRecipe.create(AbstractRecipe.java:108) ~[!/:1.10.3]
                at org.apache.aries.blueprint.container.BeanRecipe.setProperty(BeanRecipe.java:810) ~[!/:1.10.3]
                at org.apache.aries.blueprint.container.BeanRecipe.setProperties(BeanRecipe.java:784) ~[!/:1.10.3]
                at org.apache.aries.blueprint.container.BeanRecipe.setProperties(BeanRecipe.java:765) ~[!/:1.10.3]
                at org.apache.aries.blueprint.container.BeanRecipe.internalCreate2(BeanRecipe.java:699) ~[!/:1.10.3]
                at org.apache.aries.blueprint.container.BeanRecipe.internalCreate(BeanRecipe.java:666) ~[!/:1.10.3]
                at org.apache.aries.blueprint.di.AbstractRecipe.call(AbstractRecipe.java:81) ~[!/:1.10.3]
                at java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[?:?]
                at org.apache.aries.blueprint.di.AbstractRecipe.create(AbstractRecipe.java:90) ~[!/:1.10.3]
                at org.apache.aries.blueprint.di.RefRecipe.internalCreate(RefRecipe.java:62) ~[!/:1.10.3]
                at org.apache.aries.blueprint.di.AbstractRecipe.create(AbstractRecipe.java:108) ~[!/:1.10.3]
                at org.apache.aries.blueprint.container.BeanRecipe.setProperty(BeanRecipe.java:810) ~[!/:1.10.3]
                at org.apache.aries.blueprint.container.BeanRecipe.setProperties(BeanRecipe.java:784) ~[!/:1.10.3]
                at org.apache.aries.blueprint.container.BeanRecipe.setProperties(BeanRecipe.java:765) ~[!/:1.10.3]
                at org.apache.aries.blueprint.container.BeanRecipe.internalCreate2(BeanRecipe.java:699) ~[!/:1.10.3]
                at org.apache.aries.blueprint.container.BeanRecipe.internalCreate(BeanRecipe.java:666) ~[!/:1.10.3]
                at org.apache.aries.blueprint.di.AbstractRecipe.call(AbstractRecipe.java:81) ~[!/:1.10.3]
                at java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[?:?]
                at org.apache.aries.blueprint.di.AbstractRecipe.create(AbstractRecipe.java:90) ~[!/:1.10.3]
                at org.apache.aries.blueprint.container.BlueprintRepository.createInstances(BlueprintRepository.java:360) ~[!/:1.10.3]
                at org.apache.aries.blueprint.container.BlueprintRepository.createAll(BlueprintRepository.java:190) ~[!/:1.10.3]
                at org.apache.aries.blueprint.container.BlueprintContainerImpl.instantiateEagerComponents(BlueprintContainerImpl.java:737) ~[!/:1.10.3]
                at org.apache.aries.blueprint.container.BlueprintContainerImpl.doRun(BlueprintContainerImpl.java:433) [!/:1.10.3]
                at org.apache.aries.blueprint.container.BlueprintContainerImpl.run(BlueprintContainerImpl.java:298) [!/:1.10.3]
                at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) [?:?]
                at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
                at org.apache.aries.blueprint.container.ExecutorServiceWrapper.run(ExecutorServiceWrapper.java:106) [!/:1.10.3]
                at org.apache.aries.blueprint.utils.threading.impl.DiscardableRunnable.run(DiscardableRunnable.java:45) [!/:1.10.3]
                at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) [?:?]
                at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
                at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) [?:?]
                at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
                at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
                at java.lang.Thread.run(Thread.java:834) [?:?]
            Caused by: java.lang.IllegalArgumentException: filters is not an ordered map. Please try java.util.LinkedHashMap.
                at org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder.setFilters(DefaultIoFilterChainBuilder.java:428) ~[?:?]
                at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
                at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
                at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
                at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
                at org.apache.aries.blueprint.utils.ReflectionUtils$MethodPropertyDescriptor.internalSet(ReflectionUtils.java:668) ~[!/:1.10.3]
                at org.apache.aries.blueprint.utils.ReflectionUtils$PropertyDescriptor.set(ReflectionUtils.java:418) ~[!/:1.10.3]
                at org.apache.aries.blueprint.container.BeanRecipe.setProperty(BeanRecipe.java:816) ~[!/:1.10.3]
                ... 42 more

这是错误内容的 xml 语法。

        <bean id="myCodec" class="org.apache.mina.filter.codec.ProtocolCodecFilter">
            <argument>
                <bean class="com.my.project.core.message.RProtocolCodecFactory"/>
            </argument>
        </bean>
        
        <bean id="filters" class="org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder">
            <property name="filters">
                <map key-type="java.lang.String" value-type="org.apache.mina.filter.codec.ProtocolCodecFilter">
                    <entry key="codecFilter" value-ref="myCodec"/>
                </map>
            </property>
        </bean>

当更改日志级别调试时,我看到以下日志。

DEBUG [Blueprint Extender: 1] java.util.HashMap is not a LinkedHashMap.

DEBUG [Blueprint Extender: 1] java.util.HashMap doesn't implement OrderedMap interface.

DEBUG [Blueprint Extender: 1] Last resort; trying to create a new map instance with a default constructor and test if insertion order is maintained.

DEBUG [Blueprint Extender: 1] The specified map didn't pass the insertion order test after 3 tries.

此 DEBUG 日志写在 org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder.java

class.

中有这样的注解和方法
    @SuppressWarnings("unchecked")
    private boolean isOrderedMap(Map<String,? extends IoFilter> map) {
        if (map == null) {
            return false;
        }
        
        Class<?> mapType = map.getClass();
        
        if (LinkedHashMap.class.isAssignableFrom(mapType)) {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("{} is an ordered map.", mapType.getSimpleName() );
            }
            
            return true;
        }

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("{} is not a {}", mapType.getName(), LinkedHashMap.class.getSimpleName());
        }

        // Detect Jakarta Commons Collections OrderedMap implementations.
        Class<?> type = mapType;
        
        while (type != null) {
            for (Class<?> i : type.getInterfaces()) {
                if (i.getName().endsWith("OrderedMap")) {
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("{} is an ordered map (guessed from that it implements OrderedMap interface.)",
                                mapType.getSimpleName());
                    }
                    
                    return true;
                }
            }
            
            type = type.getSuperclass();
        }

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("{} doesn't implement OrderedMap interface.", mapType.getName() );
        }

        // Last resort: try to create a new instance and test if it maintains
        // the insertion order.
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Last resort; trying to create a new map instance with a "
                    + "default constructor and test if insertion order is maintained.");
        }

        Map<String,IoFilter> newMap;
        
        try {
            newMap = (Map<String,IoFilter>) mapType.newInstance();
        } catch (Exception e) {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Failed to create a new map instance of '{}'.", mapType.getName(), e);
            }
            
            return false;
        }

        Random rand = new Random();
        List<String> expectedNames = new ArrayList<>();
        IoFilter dummyFilter = new IoFilterAdapter();
        
        for (int i = 0; i < 65536; i++) {
            String filterName;
            
            do {
                filterName = String.valueOf(rand.nextInt());
            } while (newMap.containsKey(filterName));

            newMap.put(filterName, dummyFilter);
            expectedNames.add(filterName);

            Iterator<String> it = expectedNames.iterator();
            
            for (Object key : newMap.keySet()) {
                if (!it.next().equals(key)) {
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("The specified map didn't pass the insertion order test after {} tries.", (i + 1));
                    }
                    
                    return false;
                }
            }
        }

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("The specified map passed the insertion order test.");
        }
        
        return true;
    }

“检测 Jakarta Commons Collections OrderedMap 实现”

如果注入的类型不是OrderedMap,可以看到正在尝试创建一个新的Map。

使用现有的Spring DM属性时,希望创建相同的新地图并尝试,但没有失败。

为什么?使用 Blueprint 属性 时会失败吗?

我错过了什么?有更好的选择吗?

这几天解决其他问题回来,看了看OSGI 7标准的指导文档,很简单的一道题

<bean id="filter" class="java.util.LinkedHashMap">
    <argument>
        <map>
            <entry key="codecFilter" value-ref="dfCodec"/>
        </map>
    </argument>

</bean>

<bean id="filters"
      class="org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder">
    <property name="filters" ref="filter"/>
</bean>

效果不错