【问题标题】:How can I programmatically get beans from an OSGI blueprint?如何以编程方式从 OSGI 蓝图中获取 bean?
【发布时间】:2017-10-23 07:44:11
【问题描述】:

出于测试目的,我想在 Apache Camel 应用程序的蓝图中获取 bean 的实例。

在 JUnit 测试中,如何在下面的 daos.xml 中获取 bean 的实例,因为它们将存在于应用程序的 OSGI 容器中?

种类

AuditPageNavDao aDao = Daos.getInstance("auditPageNavDao");

我有一个带有插件的 Maven pom.xml:

<plugin>
    <groupId>org.apache.felix</groupId>
    <artifactId>maven-bundle-plugin</artifactId>
    <extensions>true</extensions>
    <configuration>
        <instructions>
            <Bundle-Name>DaoServicesCommon</Bundle-Name>
            <Bundle-Activator>com.acme.dao.bundle.Activator</Bundle-Activator>
            <Meta-Persistence>META-INF/persistence.xml</Meta-Persistence>
            <Import-Package>
                javax.persistence,
                org.hibernate.proxy,
                javassist.util.proxy,
                *
            </Import-Package>
        </instructions>
    </configuration>
</plugin>

META-INF/persistence.xml 看起来像

<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
    version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">

    <persistence-unit name="appPU" transaction-type="JTA">
        <jta-data-source>osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=jdbc/appxadb)</jta-data-source>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
            <property name="hibernate.enable_lazy_load_no_trans" value="true" />
            <property name="show_sql" value="true" />
        </properties>
    </persistence-unit>

</persistence>

OSGI-INF/blueprint/daos.xml 看起来像

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
    xmlns:jpa="http://aries.apache.org/xmlns/jpa/v1.1.0" xmlns:tx="http://aries.apache.org/xmlns/transactions/v1.2.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
        http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint-2.8.0.xsd
        http://aries.apache.org/xmlns/transactions/v1.2.0 http://aries.apache.org/schemas/transaction/transactionv12.xsd
        http://aries.apache.org/xmlns/jpa/v1.1.0 http://aries.apache.org/schemas/jpa/jpa_110.xsd">

    <!-- AUDIT DAO SERVICES -->
    <bean id="auditAccountTxnDao" class="com.acme.dao.audit.jta.AuditAccountTxnDaoImpl">
        <argument index="0" ref="temporals" />
        <jpa:context index="1" unitname="appPU" />
    </bean>

    <service interface="com.acme.dao.audit.jta.AuditAccountTxnDao"
        ref="auditAccountTxnDao">
        <service-properties>
            <entry key="osgi.jndi.service.name" value="AuditAccountTxnDao" />
        </service-properties>
    </service>

    <bean id="auditAuthDao" class="com.acme.dao.audit.jta.AuditAuthDaoImpl">
        <argument index="0" ref="temporals" />
        <jpa:context index="1" unitname="appPU" />
    </bean>

    <service interface="com.acme.dao.audit.jta.AuditAuthDao"
        ref="auditAuthDao">
        <service-properties>
            <entry key="osgi.jndi.service.name" value="AuditAuthDao" />
        </service-properties>
    </service>

    <bean id="auditPageNavDao" class="com.acme.dao.audit.jta.AuditPageNavDaoImpl">
        <argument index="0" ref="temporals" />
        <jpa:context index="1" unitname="appPU" />
    </bean>

    <service interface="com.acme.dao.audit.jta.AuditPageNavDao"
        ref="auditPageNavDao">
        <service-properties>
            <entry key="osgi.jndi.service.name" value="AuditPageNavDao" />
        </service-properties>
    </service>

    <bean id="auditTxnDao" class="com.acme.dao.audit.jta.AuditTxnDaoImpl">
        <argument index="0" ref="temporals" />
        <jpa:context index="1" unitname="appPU" />
    </bean>

    <service interface="com.acme.dao.audit.jta.AuditTxnDao"
        ref="auditTxnDao">
        <service-properties>
            <entry key="osgi.jndi.service.name" value="AuditTxnDao" />
        </service-properties>
    </service>

    <bean id="auditEventCodeDao" class="com.acme.dao.audit.jta.AuditEventCodeDaoImpl">
        <argument index="0" ref="temporals" />
        <jpa:context index="1" unitname="appPU" />
    </bean>

    <service interface="com.acme.dao.audit.jta.AuditEventCodeDao"
        ref="auditEventCodeDao">
        <service-properties>
            <entry key="osgi.jndi.service.name" value="AuditEventCodeDao" />
        </service-properties>
    </service>

</blueprint>

最后激活器是

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

public class Activator implements BundleActivator
{

    @Override
    public void start(final BundleContext context) throws Exception
    {
    }

    @Override
    public void stop(final BundleContext context) throws Exception
    {
    }

}

【问题讨论】:

  • 您的测试是在 OSGi 内部(使用 pax 考试)还是外部运行?
  • 理想情况下,我想使用 Eclipse“Run as JUnit”(如果可能的话)执行此操作。容器是 JBoss Fuse,在上面重新部署项目真的很痛苦。
  • 通常您可以直接从 Eclipse 运行 pax 考试测试。他们为 junit 使用了一个特殊的跑步者,但从外部(日食)他们看起来像任何其他 junit 测试。

标签: java apache-camel osgi blueprint-osgi


【解决方案1】:

这取决于您如何运行测试。有两种方式:

  • 使用 PAX EXAM,它将启动一个 OSGi 容器并在那里部署您的包
  • 使用CamelBlueprintTestSupport 类作为测试的父类,这将启动一个小型嵌入式容器来运行 Camel

您可以使用 JUnit 或 TestNG 运行测试,测试框架不相关。 另请注意,PAX EXAM 可以运行您选择的确切 JBoss Fuse 版本。

使用 PAX 考试

PAX EXAM 通过在容器内注入“探针包”来运行测试。将这个探测包想象为正在运行的测试类的“副本”。因此,在测试类中,您可以完全访问 OSGi 内部。
然后,您可以从BundleContext 向 OSGi 索要您注册的服务之一。
这是关于如何获取 auditPageNavDao bean 的粗略想法:

@RunWith(PaxExam.class)
class YourTest {
    @javax.inject.Inject
    protected BundleContext bundleContext_;

    @Test
    testMethod() {

        ServiceReference<AuditPageNavDao> daoServiceReference_ = bundleContext_.getServiceReference(AuditPageNavDao.class);
        AuditPageNavDao dao = bundleContext_.getService(daoServiceReference_);
        // use DAO here

    }
}

使用 CamelBlueprintTestSupport

您可以轻松地与组件和端点交互,例如

MyBatisComponent mbc = context.getComponent("mydb", MyBatisComponent.class);
mbc.getSqlSessionFactory().openSession().getConnection();
// don't know if this will work
Object dao = context.getRegistry().lookupByName("auditPageNavDao");

我不知道如何获取 Blueprint bean,可能CamelContext 是一个很好的起点。

【讨论】:

    【解决方案2】:

    对于 pax 考试,我建议直接注入服务。使用 Alessandro 的类作为基础。

    @RunWith(PaxExam.class)
    class YourTest {
    
        @javax.inject.Inject
        protected AuditPageNavDao dao;
    
        @Test
        testMethod() {
           // use DAO here
        }
    }
    

    这样做的好处是,只要系统中存在服务,您的 @Test 方法就会立即执行。在 Alessandro 的变体中,您的测试可能会在服务出现之前执行,从而导致 NPE。

    请注意,这种方法仅适用于服务。你不能通过这种方式简单地获得任何蓝图 bean。

    如果您需要单个 bean,您可以注入 BlueprintContainer 像上面这样的服务。每个使用蓝图的捆绑软件都会有这样的服务。您可以按服务属性进行过滤以获取特定捆绑包的 BlueprintContainer。然后用它来获取一个 bean。

    dao = container.getComponentInstance("auditAuthDao");
    

    【讨论】:

    • 是否可以使用 BlueprintContainer 让所有 bean(子类型)实现特定接口?
    猜你喜欢
    • 2014-09-04
    • 1970-01-01
    • 1970-01-01
    • 2013-10-02
    • 2017-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多