JAVA CDI 学习(3) - @Produces及@Disposes
上一节学习了注入Bean的生命周期,今天再来看看另一个话题: Bean的生产(@Produces)及销毁(@Disposes),这有点象设计模式中的工厂模式。在正式学习这个之前,先来看一个场景:
基于web的db应用开发中,经常要在一个页面上连接db,然后干点啥,最后关闭连接。下面用之前二节前到的CDI技能来演练一下:
1、先建一个Connection的接口
package conn; public interface Connection { void connect(); void closeConnection(); String doSomething(); }
Connection Interface
2、再来一个实现
package conn; import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy; public class ConnectionImpl implements Connection {
/**
* Servlet构造函数调用后,会自动执行带有@PostConstruct的方法
*/
@PostConstruct
private void initConn(){
System.out.println("initConn is called...");
connect();
} /**
* Servlet卸载前,会自动执行带有@PreDestroy的方法
*/
@PreDestroy
private void destroyConn(){
System.out.println("destroyConn is called...");
closeConnection();
} @Override
public void connect() {
System.out.println("Connecting..."); } @Override
public void closeConnection() {
System.out.println("Closing connection..."); } @Override
public String doSomething() {
String msg = "do something...";
System.out.println(msg);
return msg; } }
ConnectionImpl
注:留意一下@PostConstruct与@PreDestroy这二个特殊的注解。我们知道所有jsf/jsp页面,最终运行时,实际上执行的是背后对应的Servlet,整个Servlet的生命周期在加入了这二个注解后,其执行顺序如下:
所以,当ConnectionImpl最终被注入到Controller中时,会自动先调用initConn方法建立连接,在整个Request结束前,自动调用destroyConn关闭连接。
3、创建Controller类
package controller; import javax.inject.Inject;
import javax.inject.Named; import conn.Connection;
import conn.TestConnection; @Named("Conn")
public class ConnectionController { @Inject
private Connection connection; public Connection getConnection() {
return connection;
} }
ConnectionController
4、新建conn.xhtml用于显示
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"> <h:head>
<title>Connection Test</title>
</h:head>
<body>
#{Conn.connection.doSomething()}
</body>
</html>
conn.xhtml
eclipse里部署到jboss下,浏览http://localhost:8080/cdi-scope-sample/conn.jsf,观察console的输出:
跟预想的完全一样! 条条道路通罗马,解决问题的途径往往不止一条,或许有些人不喜欢在ConnectionImpl里参杂太多其它的职责(比如:自动打开连接、自动关闭连接),可以考虑用CDI的produces及disposes.
5、创建ConnectionFactory
回想一下设计模式中的工厂模式,对象的创建(销毁)通常放在一个单独的工厂类来处理(单一职责原则),我们也来建一个工厂:
package conn; import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.*; public class ConnectionFactory { @Produces
@RequestScoped
@MyConnection
public Connection getConn() {
System.out.println("ConnectionFactory.getConn is called...");
Connection conn = new ConnectionImpl();
conn.connect();
return conn; } public void closeConn(@Disposes @MyConnection Connection conn) {
System.out.println("ConnectionFactory.closeConn is called...");
conn.closeConnection();
} }
ConnectionFactory
注:关注一下@Produces这个注解,这表示应用该注解的方法,是一个Bean的生成器(或理解成工厂的某些产品生产流水线),在需要Inject的时候,会自动通过该方法产生对象实例;而@Disposes注解,正好与@Produces对应,用于人道毁灭@Produces产生的对象,此消彼涨,这样世界才会遵从守恒定律!
@RequestScoped不用多解释了,表示工厂里产生的Bean其生命周期仅存在于单次Http请求中。
but,just wait a minute,@MyConnection ? what is this ? why we need it ?
让我们将思维方式,从人类大脑切换成计算机电脑的模式,ConnectionImpl继承自Connection,对于系统来讲,这二个是都是兼容Connection类型的,在产生对象时,这还好说,因为目前Connection只有一个实现类ConnectionImpl,计算机可以足够智能的推断出应该用ConnectionImpl来创建对象实例,但是对象销毁的时候呢?这时传入的参数类型是Connection接口类型,这时它并不知道该对象具体是何种实现?
所以,我们自己创建了一个@MyConnection注解,在@Produces与@Disposes上都应用该注解,这样对象销毁时,就能根据该注解精确的知道是要销毁何种类型的哪个对象.
6、@MyConnection代码如下:
package conn; import java.lang.annotation.Retention;
import java.lang.annotation.Target; import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME; import javax.inject.Qualifier; @Qualifier
@Retention(RUNTIME)
@Target({ FIELD, TYPE, METHOD, PARAMETER })
public @interface MyConnection { }
@MyConnection
7、修改ConnectionController
@Inject
@MyConnection
private Connection connection;
在原来的@Inject下,增加@MyConnection,否则Controller感受不到Factory的存在(系统将只是简单的注入一个ConnectionImpl实例而已,不会自动创建连接/关闭连接),感兴趣的同学可以先不加这个注释,然后运行试试,体会一下
编译、部署、运行,观察Console的输出:
Perfect!
8、@Produces当成资源池使用
@Produces还有一个用途,可以把一些其它地方需要用到的注入对象,统一放在一起先“生产”好,形成一个"资源池",在需要使用的地方,直接从池里拿来用即可.
下面演示了这种用法:
8.1 先定义一个Product POJO类:
package model; public class Product { private String productName; private String productNo; public String getProductName() {
return productName;
} public void setProductName(String productName) {
this.productName = productName;
} public String getProductNo() {
return productNo;
} public void setProductNo(String productNo) {
this.productNo = productNo;
} @Override
public String toString() {
return productNo + "," + productName;
} }
Product
8.2 再创建一个Resocues.java,用来统一管理需要用到的资源
package resource; import javax.enterprise.inject.Produces;
import javax.inject.Named; import model.Product; public class Resouces { @Produces
@Named
public Product getNewProduct() {
Product product = new Product();
product.setProductName("new product");
product.setProductNo("000000");
return product;
} }
Resouces
8.3 然后在页面上就可以直接使用了
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jsp/jstl/core"> <h:head>
<title>CDI Sample Test</title>
</h:head>
<body>#{newProduct.toString()}
</body>
</html>
index.xhtml
注意:这里我们并没有任何的Controller,Resouces类本身也没有使用@Named之类的注解,只是在方法getNewProduct上使用了 @Produces、 @Named,页面上就可以直接使用资源池中的对象了.
JAVA CDI 学习(3) - @Produces及@Disposes的更多相关文章
- JAVA CDI 学习(4) - @Alternative/@Default/@Any & Extension
前面几节学习到的CDI内容,基本上都是hard-code,以硬编码的方式在代码里指定注入类型,这并非依赖注入的本意,依赖注入的优势之一在于“解耦”,这一节我们将学习如何利用配置来动态注入的类型及属性初 ...
- JAVA CDI 学习(1) - @Inject基本用法
CDI(Contexts and Dependency Injection 上下文依赖注入),是JAVA官方提供的依赖注入实现,可用于Dynamic Web Module中,先给3篇老外的文章,写得很 ...
- JAVA CDI 学习(2) - Scope 生命周期
在上一节中,我们已经知道了如何用@Inject实现基本注入,这一节研究Bean实例注入后的“生命周期”,web application中有几种基本的生命周期(不管哪种编程语言都类似) 1.Applic ...
- JAVA CDI 学习(5) - 如何向RESTFul Service中注入EJB实例
RESTFul Service中如果要注入EJB实例,常规的@Inject将不起作用,在Jboss中,应用甚至都启动不起来(因为@Inject注入失败),解决方法很简单:将@Inject换成@EJB ...
- Java Web 学习路线
实际上,如果时间安排合理的话,大概需要六个月左右,有些基础好,自学能力强的朋友,甚至在四个月左右就开始找工作了.大三的时候,我萌生了放弃本专业的念头,断断续续学 Java Web 累计一年半左右,总算 ...
- Java的学习之路
记事本 EditPlus eclipse Java的学习软件,已经系统性学习Java有一段时间了,接下来我想讲一下我在Java学习用到的软件. 1.第一个软件:记事本 记事本是Java学习中最基础的编 ...
- Java多线程学习笔记
进程:正在执行中的程序,其实是应用程序在内存中运行的那片空间.(只负责空间分配) 线程:进程中的一个执行单元,负责进程汇总的程序的运行,一个进程当中至少要有一个线程. 多线程:一个进程中时可以有多个线 ...
- Java基础学习-- 继承 的简单总结
代码参考:Java基础学习小记--多态 为什么要引入继承? 还是做一个媒体库,里面可以放CD,可以放DVD.如果把CD和DVD做成两个没有联系的类的话,那么在管理这个媒体库的时候,要单独做一个添加CD ...
- 20145213《Java程序设计学习笔记》第六周学习总结
20145213<Java程序设计学习笔记>第六周学习总结 说在前面的话 上篇博客中娄老师指出我因为数据结构基础薄弱,才导致对第九章内容浅尝遏止地认知.在这里我还要自我批评一下,其实我事后 ...
随机推荐
- Memcache知识点梳理
Memcache知识点梳理 Memcached概念: Memcached是一个免费开源的,高性能的,具有分布式对象的缓存系统,它可以用来保存一些经常存取的对象或数据,保存的数据像一张巨大的HAS ...
- 让你脱离google不能访问的烦恼
大陆封了google已有20多天了,给开发者带来了许多不便.只需两步让你的google可以使用: 1.设置hosts: 访问:https://git.oschina.net/kawaiiushio/m ...
- Java并发之Condition 并发同步控制
package com.thread.test.thread; import java.util.PriorityQueue; import java.util.concurrent.locks.Co ...
- Access字段类型“查阅向导”
1.显示控件有:“列表框”和“组合框”两种 2.组合框:第一个字段为“填充字段” 3.通过查阅向导建立的会自动添加“关系”(外键),因此在删除或修改字段时需要先删除二者关系,最好不通过“查阅向导”建立 ...
- coursera机器学习笔记-机器学习概论,梯度下降法
#对coursera上Andrew Ng老师开的机器学习课程的笔记和心得: #注:此笔记是我自己认为本节课里比较重要.难理解或容易忘记的内容并做了些补充,并非是课堂详细笔记和要点: #标记为<补 ...
- Storm系列(二):使用Csharp创建你的第一个Storm拓扑(wordcount)
WordCount在大数据领域就像学习一门语言时的hello world,得益于Storm的开源以及Storm.Net.Adapter,现在我们也可以像Java或Python一样,使用Csharp创建 ...
- Mysql数据库上修改日期-->造数据
这次要给客户安装测试ineedle设备,但是安装后不会立刻有数据显示,不能够全面的展示给用户web界面的一些信息.此时需要有一个公网服务器能够展示一下ineedle统计数据,但是公司58设备上没有流量 ...
- mysql 远程访问控制
如需要让192.168.2.3的test用户可以访问本机所有数据库,mysql命令如下 mysql>GRANT ALL PRIVILEGES ON *.* TO 'test'@'192.168. ...
- C++ 笔记(一) —— 尽量以 const、enum、inline 替换 #define
ilocker:关注 Android 安全(新手) QQ: 2597294287 #define ASPECT_RATIO 1.653 记号 ASPECT_RATIO 不会进入 symbol tabl ...
- vi/vim实用命令
查找 n是下一个,N是上一个 撤销和重做 u:撤销上一步的操作 ctrl+r:恢复上一步被撤销的操作 替换 :1,$ s/aaa/bbb/g