Karaf教程第9部分基于注解的blueprint和JPA

Karaf教程第9部分基于注解的blueprint和JPA

本部分演示如何用模型持久层和基于CDI注解的UI创建一个小的应用。

1 blueprint-maven-plugin

编写blueprint xml文件是很繁琐的,太大的blueprint xml文件很难与代码修改保持同步,尤其是代码重构。所以很多人喜欢使用注解来进行声明。理想情况下,这些注解应该被标准化,这样就很清晰地定义注解的功能。maven-blueprint-plugin允许使用注解配置blueprint。它会扫描一个或多个路径下的注解类,然后target/generated-resources创建blueprint.xml文件。请参阅maven-blueprint-plugin文档。

示例tasklist-blueprint-cdi

本部分演示如何用模型持久层和UI创建一个小的应用,而完全不用手动编写blueprint xml文件。

Github源代码地址:Karaf-Tutorial/tasklist-cdi-blueprint

2.1 工程结构

  • features
  • model
  • persistence
  • ui

2.2 创建bundle

这些bundle都是使用maven-bundle-plugin创建的。这个创建只在父工程使用,它会用<_include>osgi.bnd</_include>抽取OSGi配置到单独的文件。所以每一个bundle工程只需要空的、可包含额外配置的osgi.bnd文件。

由于bnd会自动计算出大多部分配置,因此osgi.bnd文件一般都比较小。

2.3 Features

定义karaf feature,安装示例以及必要的依赖。

2.4 模型

Model工程定义了Task为一个jpa实体,定义了服务接口TaskService。由于model工程不需要任何依赖注入,所以不涉及到blueprint-maven-plugin

Task JPA Entity

@Entity

public class Task {

    @Id

    Integer id;

    String title;

    String description;

    Date dueDate;

    boolean finished;

    // Getters and setters omitted

}

TaskService (Task的CRUD操作)

public interface TaskService {

    Task getTask(Integer id);

    void addTask(Task task);

    void updateTask(Task task);

    void deleteTask(Integer id);

    Collection<Task> getTasks();

}

persistence.xml

<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"

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

    xsi:schemaLocation="http://java.sun.com/xml/ns/persistencehttp://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

 

    <persistence-unit name="tasklist" transaction-type="JTA">

        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

        <jta-data-source>osgi:service/tasklist</jta-data-source>

        <properties>

            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>

            <property name="hibernate.hbm2ddl.auto" value="create-drop"/>

        </properties>

    </persistence-unit>

 

</persistence>

Persistence.xml文件定义了持久单元的名字为"tasklist",使用JTA事务。jta-data-source元素指向一个DataSource服务"tasklist"jndi名字。所以除了JTA DataSource名字,它是一个标准的hibernate 4.3风格的持久化定义,自动创建schema

另一个比较重要的事情是maven-bundle-plugin插件的配置。

配置maven bundle plugin

<Meta-Persistence>META-INF/persistence.xml</Meta-Persistence>

<Import-Package>*, org.hibernate.proxy, javassist.util.proxy</Import-Package>

Meta-Persistence指向一个persistence.xml文件, 它用于触发aries jpa创建这个BundleEntityManagerFactoryImport-Package配置导入了两个packagehibernate在运行时优化处理时需要。由于在编译时,这个优化是未知的,所以需要给maven-bundle-plugin一些提示。

2.5 持久化

tasklist-cdi-persistence bundle是这个示例当中第一个使用blueprint-maven-plugin的模块。在pom文件中,我们设置搜索路径为"net.lr.tasklist.persistence.impl"。所以所有在这个包或者子包中的类都会被扫描。

pom文件中,我们需要一个maven-bundle-plugin的特殊配置:
<Import-Package>!javax.transaction, *, javax.transaction;version="[1.1,2)"</Import-Package>
在依赖中,我们使用事务API1.2作为包含@Transactional注解的第一个规范版本。在运行时,虽然我们不需要这个注解,且karaf只提供事务API1.1版本。所以我们调整import使用karaf提供的版本。一旦事务API 1.2版本可用,这一行就不再需要了。

TaskServiceImpl

@OsgiServiceProvider(classes = {TaskService.class})

@Singleton

@Transactional

public class TaskServiceImpl implements TaskService {

    @PersistenceContext(unitName="tasklist")

    EntityManager em;

    @Override

    public Task getTask(Integer id) {

        return em.find(Task.class, id);

    }

    @Override

    public void addTask(Task task) {

        em.persist(task);

        em.flush();

    }

    // Other methods omitted

}

TaskServiceImpl使用了很多注解。使用注解@Singleton标记这个类为blueprint bean。使用注解@OsgiServiceProvider标记这个类为接口TaskServiceOSGi服务。使用注解@Transactional标记这个类支持事务操作。

所有的方法都在jta事务中执行。这意味着如果没有事务,那就会创建出来一个事务。如果已经有一个事务,那么方法就会参与其中。在事务的边界,事务要么被提交,要么因为异常而被回滚。

EntityManager用于持久单元"tasklist",被注入到字段em。它为每一个方法透明地提供一个EntityManager,按需创建,并在事务边界关闭。

InitHelper

@Singleton

public class InitHelper {

    Logger LOG = LoggerFactory.getLogger(InitHelper.class);

    @Inject TaskService taskService;

    @PostConstruct

    public void addDemoTasks() {

        try {

            Task task = new Task(1, "Just a sample task""Some more info");

            taskService.addTask(task);

        } catch (Exception e) {

            LOG.warn(e.getMessage(), e);

        }

    }

}

InitHelper类不是严格必须的。它只是简单滴创建和持久化第一个任何,这样UI就可以显示一些东西了。

@Singleton注解标记这个类作为一个blueprint bean创建。
@Inject TaskService taskService
注入在blueprint上下文中找到的第一个类型为TaskServicebean,并赋给字段taskService
@PostConstruct
注解确保在这个bean的所有字段都被注入后,调用addDemoTasks()方法。

另一件有趣的事情是模块中的测试类TaskServiceImplTest。它在OSGi之外运行,使用特殊的persistence.xml用于测试时创建EntityManagerFactory,而不需要jndi DataSource,因为这个很难提供。它也使用了RESOURCE_LOCAL事务,这样我们就不需要创建事务管理。测试注入了普通的EntityManger对象到TaskServiceImpl类中。所以我们必须手动开启事务和提交事务。这个例子说明了用普通的java测试JPA代码,测试简单快速。

2.6 Servlet UI

tasklist-ui模块使用OSGi service TaskServicePax-web whiteboard bundle会检测导出的servlet,并使用HttpService发布它。在pom文件中,这个模块需要blueprint-maven-plugin有适当的scanPath

TasklistServlet

@OsgiServiceProvider(classes={Servlet.class})

@Properties({@Property(name="alias", value="/tasklist")})

@Singleton

public class TaskListServlet extends HttpServlet {

    @Inject @OsgiService

    TaskService taskService;

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,

        IOException {

        // Actual code omitted

    }

}

TaskListServlet用接口javax.servlet.Servlet导出,服务属性别名为"/tasklist"。这样,通过http://localhost:8181/tasklist就可以访问到。

@Inject @OsgiService TaskService taskService这条语句会创建一个blueprint的引用元素,导入TaskService接口定义的OSGI服务。然后,这个服务就被注入到上面这个类的taskService字段。如果这个接口存在多个服务实例,那么filter属性可用于选择使用哪一个。

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值