教程:编写自己的CDI扩展

今天,我将向您展示如何编写CDI扩展。

CDI提供了一种扩展功能的简便方法,例如

  • 添加自己的范围,
  • 启用Java核心类进行扩展,
  • 使用注释元数据进行扩充或修改,
  • 以及更多。

在本教程中,我们将实现一个扩展,该扩展将从属性文件中注入属性,就像往常一样,我将在github [更新: sources @ github ]中提供源。

目标

提供扩展,使我们能够执行以下操作

@PropertyFile("myProps.txt")
public class MyProperties {@Property("version")Integer version;@Property("appname")String appname;
}

其中版本应用程序的名字在文件myProps.txt定义。

制备

首先,我们需要CDI API的依赖项

dependencies.compile "javax.enterprise:cdi-api:1.1-20130918"

现在我们可以开始了。 让我们

弄湿

基础

每个CDI扩展的入口点都是一个实现javax.enterprise.inject.spi.Extension的类

package com.coderskitchen.propertyloader;import javax.enterprise.inject.spi.Extension;
public class PropertyLoaderExtension implements Extension {
//  More code later
}

另外,我们必须将此类的全限定名添加到META-INF / services目录中名为javax.enterprise.inject.spi.Extension的文件中。

javax.enterprise.inject.spi.Extension

com.coderskitchen.propertyloader.PropertyLoaderExtension

这些是编写CDI扩展的基本步骤。

背景资料
CDI使用Java SE的服务提供商体系结构,这就是为什么我们需要实现标记接口并在实现类的FQN中添加文件的原因。

潜水更深

现在,我们必须选择正确的事件来收听。

背景资料
CDI规范定义了几个事件,这些事件在应用程序初始化期间由容器触发。
例如,在容器以bean发现开始之前,将触发BeforeBeanDiscovery

对于本教程,我们需要监听ProcessInjectionTarget事件。 对于发现的每个Java类,接口或枚举,将触发此事件,并且可能在运行时由容器实例化该事件。
因此,让我们添加此事件的观察者:

public <T> void initializePropertyLoading(final @Observes ProcessInjectionTarget<T> pit) {
}

ProcessInjectionTarget通过getAnnotatedType方法授予对基础类的访问权限,并通过getInjectionTarget授予创建中的实例的访问权限 我们使用annotatedType获取类上的注释,以检查@PropertyFile是否可用。 如果没有,我们将直接作为短路返回。

随后, InjectionTarget用于覆盖当前行为并从属性文件中设置值。

public <T> void initializePropertyLoading(final @Observes ProcessInjectionTarget<T> pit) {AnnotatedType<T> at = pit.getAnnotatedType();if(!at.isAnnotationPresent(PropertyFile.class)) {return;}}

在本教程中,我们假定属性文件直接位于类路径的根目录中。 基于此假设,我们可以添加以下代码以从文件中加载属性

PropertyFile propertyFile = at.getAnnotation(PropertyFile.class);
String filename = propertyFile.value();
InputStream propertiesStream = getClass().getResourceAsStream("/" + filename);
Properties properties = new Properties();
try {properties.load(propertiesStream);assignPropertiesToFields(at.getFields, properties); // Implementation follows
} catch (IOException e) {e.printStackTrace();
}

现在,我们可以将属性值分配给字段。 但是对于CDI,我们必须以略有不同的方式执行此操作。 我们应该使用InjectionTarget并覆盖当前的AnnotatedType。 这使CDI可以确保所有事情都可以按正确的顺序进行。

为了实现这一点,我们使用了最终的Map <Field,Object> ,我们可以在其中存储当前分配以供以后在InjectionTarget中使用 。 映射是在方法AssignPropertiesToFields中完成的。

private <T> void assignPropertiesToFields(Set<AnnotatedField<? super T>> fields, Properties properties) {for (AnnotatedField<? super T> field : fields) {if(field.isAnnotationPresent(Property.class)) {Property property = field.getAnnotation(Property.class);String value = properties.getProperty(property.value());Type baseType = field.getBaseType();fieldValues.put(memberField, value);}}

最后,我们现在将创建一个新的InjectionTarget,以将字段值分配给所有新创建的基础类实例。

final InjectionTarget<T> it = pit.getInjectionTarget();InjectionTarget<T> wrapped = new InjectionTarget<T>() {@Overridepublic void inject(T instance, CreationalContext<T> ctx) {it.inject(instance, ctx);for (Map.Entry<Field, Object> property: fieldValues.entrySet()) {try {Field key = property.getKey();key.setAccessible(true);Class<?> baseType = key.getType();String value = property.getValue().toString();if (baseType == String.class) {key.set(instance, value);}  else if (baseType == Integer.class) {key.set(instance, Integer.valueOf(value));} else {pit.addDefinitionError(new InjectionException("Type " + baseType + " of Field " + key.getName() + " not recognized yet!"));}} catch (Exception e) {pit.addDefinitionError(new InjectionException(e));}}}@Overridepublic void postConstruct(T instance) {it.postConstruct(instance);}@Overridepublic void preDestroy(T instance) {it.dispose(instance);}@Overridepublic void dispose(T instance) {it.dispose(instance);}@Overridepublic Set<InjectionPoint> getInjectionPoints() {return it.getInjectionPoints();}@Overridepublic T produce(CreationalContext<T> ctx) {return it.produce(ctx);}};pit.setInjectionTarget(wrapped);

这就是做魔术的全部。 最后,这里是ProperyLoaderExtension的完整代码。

PropertyLoaderExtension

package com.coderskitchen.propertyloader;import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.InjectionException;
import javax.enterprise.inject.spi.AnnotatedField;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.enterprise.inject.spi.InjectionTarget;
import javax.enterprise.inject.spi.ProcessInjectionTarget;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;public class PropertyLoaderExtension implements Extension {final Map<Field, Object> fieldValues = new HashMap<Field, Object>();public <T> void initializePropertyLoading(final @Observes ProcessInjectionTarget<T> pit) {AnnotatedType<T> at = pit.getAnnotatedType();if(!at.isAnnotationPresent(PropertyyFile.class)) {return;}PropertyyFile propertyyFile = at.getAnnotation(PropertyyFile.class);String filename = propertyyFile.value();InputStream propertiesStream = getClass().getResourceAsStream("/" + filename);Properties properties = new Properties();try {properties.load(propertiesStream);assignPropertiesToFields(at.getFields(), properties);} catch (IOException e) {e.printStackTrace();}final InjectionTarget<T> it = pit.getInjectionTarget();InjectionTarget<T> wrapped = new InjectionTarget<T>() {@Overridepublic void inject(T instance, CreationalContext<T> ctx) {it.inject(instance, ctx);for (Map.Entry<Field, Object> property: fieldValues.entrySet()) {try {Field key = property.getKey();key.setAccessible(true);Class<?> baseType = key.getType();String value = property.getValue().toString();if (baseType == String.class) {key.set(instance, value);}  else if (baseType == Integer.class) {key.set(instance, Integer.valueOf(value));} else {pit.addDefinitionError(new InjectionException("Type " + baseType + " of Field " + key.getName() + " not recognized yet!"));}} catch (Exception e) {pit.addDefinitionError(new InjectionException(e));}}}@Overridepublic void postConstruct(T instance) {it.postConstruct(instance);}@Overridepublic void preDestroy(T instance) {it.dispose(instance);}@Overridepublic void dispose(T instance) {it.dispose(instance);}@Overridepublic Set<InjectionPoint> getInjectionPoints() {return it.getInjectionPoints();}@Overridepublic T produce(CreationalContext<T> ctx) {return it.produce(ctx);}};pit.setInjectionTarget(wrapped);}private <T> void assignPropertiesToFields(Set<AnnotatedField<? super T>> fields, Properties properties) {for (AnnotatedField<? super T> field : fields) {if(field.isAnnotationPresent(Propertyy.class)) {Propertyy propertyy = field.getAnnotation(Propertyy.class);Object value = properties.get(propertyy.value());Field memberField = field.getJavaMember();fieldValues.put(memberField, value);}}}
}

资料下载

完整的源代码将在git hub上提供,直到星期一晚上。 jar存档可在此处PropertyLoaderExtension中找到 。

最后的笔记

本教程说明了如何轻松地向CDI框架添加新功能。 在几行代码中,添加了工作属性加载和注入机制。 在应用程序的生命周期中触发的事件提供了一种松散耦合且功能强大的方法来添加新功能,拦截bean创建或更改行为。

属性注入也可以通过引入一组生产者方法来实现,但是这种方法需要每个字段类型一个生产者方法。 使用这种通用方法,您只需要添加新的转换器即可启用其他类型的值的注入。

参考: 教程:从我们的JCG合作伙伴 Peter Daum在Coders Kitchen博客上编写自己的CDI扩展 。

翻译自: https://www.javacodegeeks.com/2014/02/tutorial-writing-your-own-cdi-extension.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/365327.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c调用python脚本 效率,尝试用C调用Python脚本#

我正在制作一个迷你Python IDE来好玩。为什么不。所以我希望能够从C调用一个python脚本&#xff0c;现在我只测试一个简单的场景。我知道这不是专业IDE的工作原理。在private void Run_Click(object sender, EventArgs e){run_cmd("C:/Python34/python.exe", "C…

Hyhyhy – 专业的 HTML5 演示文稿工具

Hyhyhy 是创建好看的 HTML5 演示文档的工具。它具备很多的特点&#xff1a;支持 Markdown&#xff0c;嵌套幻灯片&#xff0c;数学排版&#xff0c;兼容性&#xff0c;语法高亮&#xff0c;使用 Javascript API &#xff0c;方便的骨架。它支持 Firefox 2 , Safari 3 , Opera 9…

POJ 1258 Agri-Net (最小生成树)

题目&#xff1a; Description Farmer John has been elected mayor of his town! One of his campaign promises was to bring internet connectivity to all farms in the area. He needs your help, of course. Farmer John ordered a high speed connection for his farm a…

python人工智能炒期货_学会用Python结合人工智能尝试预测股票,下一个股神就是你!...

股票市场涨涨跌跌&#xff0c;好像毫无规律&#xff0c;但有一些人却凭借自己的直觉掌握了一些特殊规律&#xff0c;从而实现在股票上的实现斩获。现在在人工智能时代&#xff0c;PythonAI框架&#xff0c;无疑会利用人工智能优势可以对股票市场进行特征学习&#xff0c;抓取比…

JAX-RS 2.0中的透明PATCH支持

PATCH方法是最不受欢迎的HTTP方法之一&#xff0c;因为直到最近才真正没有一种标准的PATCH格式。 一段时间以来&#xff0c;它已经针对JSON进行了标准化&#xff0c;因此有很多库可以为您完成繁重的工作。 出于本博客的目的&#xff0c;我将使用json-patch&#xff0c;尽管可以…

Java开发知识之Java的枚举

Java开发知识之Java的枚举 一丶什么是枚举 枚举可以理解为就是常量,在Java中我们定义常量.都是用 final语句. C中都是用const关键字. 枚举跟C概念都是一样的.就是特定的常量而已. 二丶Java中的枚举 java中的常量.一般都是final定义.但是我们讲过.final定义的常量.初始化的时候可…

linux php7 mongodb,CentOS 7下安装配置PHP7跟LAMP及MongoDB和Redis

CentOS 7下安装配置PHP7跟LAMP及MongoDB和Redis我是想能yum就yum&#xff0c;所有软件的版本一直会升级&#xff0c;注意自己当时的版本是不是已经更新了。首先装CentOS 7装好centos7后默认是不能上网的cd /etc/sysconfig/network-scripts/找到形如ifcfg-enp0s3的文件&#xff…

【汇总目录】C#

[2019年04月29日] C# textbox 自动滚动 [2019年02月07日] C#利用VUDP.cs开发网络通讯应用程序 [2019年02月06日] C#利用VINI.cs操作INI文件 [2018年12月19日] 控件数组批量生成控件 转载于:https://www.cnblogs.com/velscode/p/10535101.html

基于 Bootstrap 的响应式后台管理面板

你想建立一个后台管理面板或者分析仪表板吗&#xff1f;不需从头开始&#xff0c;Keen IO Bootstrap 是一个响应式的仪表盘模板&#xff0c;可以帮助你在几分钟内呈现数据&#xff0c;让你可以创建一个有吸引力的&#xff0c;定制的分析仪表板&#xff0c;随时可以展现给你的团…

Java:AspectJ的异常翻译

在这篇博客文章中&#xff0c;我描述了如何使用AspectJ自动将一种异常类型转换为另一种异常类型。 问题 有时&#xff0c;我们处于必须将异常&#xff08;通常由第三方库引发&#xff09;转换为另一种异常的情况。 假设您使用的是诸如hibernate之类的持久性框架&#xff0c;并…

sparkstreaming监听hdfs目录_大数据系列之Spark Streaming接入Kafka数据

Spark Streaming官方提供Receiver-based和Direct Approach两种方法接入Kafka数据&#xff0c;本文简单介绍两种方式的pyspark实现。1、Spark Streaming接入Kafka方式介绍Spark Streaming 官方提供了两种方式读取Kafka数据&#xff1a;一是Receiver-based Approach。该种读取模式…

php职业认证,如何用 PHP 进行 HTTP 认证

PHP 的 HTTP 认证机制在 PHP 以 Apache 模块方式运行时才有效&#xff0c;因此该功能不适用于 CGI 版本。在 Apache 模块的 PHP 脚本中&#xff0c;可以用 header() 函数来向客户端浏览器发送“Authentication Required”信息&#xff0c;使其弹出一个用户名/密码输入窗口。当用…

时间服务器

时间服务器配置&#xff1a; 1 安装软件包: [rootlocalhost ~]# yum install ntp –y 2 修改配置文件 [rootlocalhost ~]# vim /etc/ntp.conf # 允许内网其他机器同步时间 192.168.1.0该网段 restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap 允许任何ip的客户机都可以…

使用 HTML5 Canvas 绘制出惊艳的水滴效果

HTML5 在不久前正式成为推荐标准&#xff0c;标志着全新的 Web 时代已经来临。在众多 HTML5 特性中&#xff0c;Canvas 元素用于在网页上绘制图形&#xff0c;该元素标签强大之处在于可以直接在 HTML 上进行图形操作&#xff0c;具有极大的应用价值。 这里分享一个惊艳的 Canva…

Java EE 8:社区想要什么?

在进行了之前的两次社区调查之后&#xff0c;第一次调查于2013年12月发布&#xff0c;第二次调查于2014年1月发布&#xff0c;Oracle呼吁企业社区对Java EE 8进行第三次也是最后一次调查 。该调查的截止日期为2014年3月24日&#xff0c;12日。太平洋时间。 值得注意的是&#…

mysql 字符串类型 char varchar

字符类型用在存储名字、邮箱地址、家庭住址等描述性数据 char指的是定长字符&#xff0c;varchar指的是变长字符 #官网&#xff1a;https://dev.mysql.com/doc/refman/5.7/en/char.html #注意&#xff1a;char和varchar括号内的参数指的都是字符的长度#char类型&#xff1a;定长…

二叉树遍历规则

树的遍历顺序大体分为三种&#xff1a;前序遍历&#xff08;先根遍历、先序遍历&#xff09;&#xff0c;中序遍历&#xff08;中根遍历&#xff09;&#xff0c;后序遍历&#xff08;后根遍历&#xff09;。 如图所示二叉树&#xff1a; 前序遍历&#xff1a;前序遍历可以记为…

vue vue的table表格自适应_vue table autoHeight(vue 表格自动高度)

小编主要做的都是后台管理系统&#xff0c;采用布局多为头部、左侧菜单栏&#xff0c;右侧内容&#xff0c;头部和菜单栏固定位置&#xff0c;内容部分如果很长就会出现滚动条(iview和element都提供了布局容器)&#xff0c;后台管理系统多为表格的增删改查&#xff0c;so&#…

php网页的注册界面设计,HTML开发博客之注册页面设计(一)

CSS文件的引入新建文件reg.html文件首先我们来分析网页布局这是我们页面完成后的效果&#xff0c;网页分为三部分头部&#xff0c;主体&#xff0c;和底部我们按照这个顺序开始编写。头部导航栏的编写html>用户注册页面首页科技资讯心情随笔资源收藏图文图片留言板登陆/注册…

Arctext.js - 基于 CSS3 jQuery 的文本弯曲效果

Arctext.js 是基于 Lettering.js 的文本旋转插件&#xff0c;根据设置的旋转半径准确计算每个字母的旋转弧度并均匀分布。虽然 CSS3 也能够实现字符旋转效果&#xff0c;但是要让安排每个字母都沿着弯曲路径排布相当的复杂&#xff0c;结合 Arctext.js 则可以轻松实现这个效果。…