工作总结4:拦截器的使用

1.拦截器综述

拦截器的功能是定义在Java拦截器规范。

拦截器规范定义了三种拦截点:

业务方法拦截,
生命周期回调侦听,
超时拦截(EJB)方法。
在容器的生命周期中进行拦截

public class DependencyInjectionInterceptor {@PostConstructpublic void injectDependencies(InvocationContext ctx) { ... }
}

EJB超时时使用的拦截器

public class TimeoutInterceptor {@AroundTimeoutpublic Object manageTransaction(InvocationContext ctx) throws Exception { ... }
}

在业务上,对某一个Bean的方法进行拦截

public class TransactionInterceptor {@AroundInvokepublic Object manageTransaction(InvocationContext ctx) throws Exception { ... }
}

@AroundInvoke注释指定了要用作拦截器的方法,拦截器方法与被拦截的业务方法执行同一个java调用堆栈、同一个事务和安全上下文中。用@AroundInvoke注释指定的方法必须遵守以下格式:public Object XXX(javax.interceptor.InvocationContext ctx) throws Exception

下面是javax.interceptor.InvocationContext封装了客户端所调用业务方法的一些信息。

package javax.interceptor;
public interface InvocationContext{public Object getTarget();public Method getMethod();public Ojbect[] getParameters();public void setParameters(Object[] newArgs);public java.util.Map<String, Ojbect> getContextData();public Object proceed() throws Exception;
}

getTarget() 指向被调用的bean实例
getMethod() 指向被拦截的业务方法
getParameters() 获取被拦截业务方法的参数
setParameters() 设置被拦截业务方法的参数
getContextData() 返回一个Map对象,它在整个方法调用期间都可以被访问到。位于同一个方法调用内的不同拦截器之间可以利用它来传递上下文相关的数据。
示例:

//被拦截的方法
@Interceptors(HelloInterceptor.class)
public class HelloChinaBean {public String SayHello(String name) {return name +"Hello World.";}
}
//拦截器定义
public class HelloInterceptor {@AroundInvokepublic Object log(InvocationContext ctx) throws Exception {try{if (ctx.getMethod().getName().equals("SayHello")){System.out.println("Holle World!!!" );}           return ctx.proceed();}catch (Exception e) {throw e;}}
}

2.拦截器绑定(Interceptor bindings)

假设我们想要申明一些bean的事务。我们先要的是一个拦截器绑定类型来指定哪些bean我们要申明.
首先定义一个注解

@InterceptorBinding
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Transactional {}
现在我们可以很容易地指定类ShoppingCart是事务性对象: 

@Transactional public class ShoppingCart { ... } 或者我们可以指定一个方法的事务

public class ShoppingCart {@Transactional public void checkout() { ... }
}
  • 1
  • 2
  • 3

2.拦截器实现(Implementing interceptors)

我们实际上要实现提供了这种事务管理方面的拦截器,所以我们需要做的是创建一个标准的拦截,并配上@Interceptor和@transactional注解.

@Transactional @Interceptor
public class TransactionInterceptor {@AroundInvokepublic Object manageTransaction(InvocationContext ctx) throws Exception { ... }
}

拦截器可以利用依赖注入:

@Transactional @Interceptor
public class TransactionInterceptor {@Resource UserTransaction transaction;@AroundInvokepublic Object manageTransaction(InvocationContext ctx) throws Exception { ... }
}

多个拦截器可以使用相同的拦截器绑定类型。

@Resource和@Inject的区别:

3.启用拦截器(Enabling interceptors)

默认情况下,所有拦截器被禁用.要使用拦截器.需要在bean.xml中进行配置,以启用.从CDI 1.1起拦截器可以使用@Priority注释为整个应用程序启用。

<beansxmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaeehttp://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"><interceptors><class>org.mycompany.myapp.TransactionInterceptor</class></interceptors>
</beans>

这样有2个好处:

拦截器比较重要,在XML中确保其确定性行为
它让我们在部署时启用或禁用拦截器类。
当然也可以配置启用多个拦截器

<beansxmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaeehttp://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"><interceptors><class>org.mycompany.myapp.SecurityInterceptor</class><class>org.mycompany.myapp.TransactionInterceptor</class></interceptors>
</beans>

拦截器毕竟比较重要,不推荐使用@Priority启用.
在CDI中,XML配置的优先级高于@Priority.
关于@Priority可以参考下列:

public static class Interceptor.Priority
extends Object
Priorities that define the order in which interceptors are invoked. These values should be used with the Priority annotation.

Interceptors defined by platform specifications should have priority values in the range PLATFORM_BEFORE up until LIBRARY_BEFORE, or starting at PLATFORM_AFTER.
Interceptors defined by extension libraries should have priority values in the range LIBRARY_BEFORE up until APPLICATION, or LIBRARY_AFTER up until PLATFORM_AFTER.
Interceptors defined by applications should have priority values in the range APPLICATION up until LIBRARY_AFTER.
An interceptor that must be invoked before or after another defined interceptor can choose any appropriate value.

Interceptors with smaller priority values are called first. If more than one interceptor has the same priority, the relative order of these interceptor is undefined.

For example, an extension library might define an interceptor like this:

@Priority(Interceptor.Priority.LIBRARY_BEFORE+10)@Interceptorpublic class ValidationInterceptor { ... }

4.Interceptor bindings with members(拦截器注解属性)
假设我们想要添加一些额外的信息给我们的@transactional注解:

@InterceptorBinding
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Transactional {boolean requiresNew() default false;
}

CDI将使用requiresNew的值选择两个不同的拦截器,TransactionInterceptor和RequiresNewTransactionInterceptor

下面是requiresNew为true的拦截器

@Transactional(requiresNew = true) @Interceptor
public class RequiresNewTransactionInterceptor {@AroundInvokepublic Object manageTransaction(InvocationContext ctx) throws Exception { ... }
}

如下使用:

@Transactional(requiresNew = true)
public class ShoppingCart { ... }

但是如果我们只有一个拦截器,我们希望容器拦截器绑定时忽略requiresNew的值,也许这些信息只用于拦截器实现。我们可以使用@Nonbinding注释:

@InterceptorBinding
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Secure {@Nonbinding String[] rolesAllowed() default {};
}

5.Multiple interceptor binding annotations(多重拦截器绑定注解)

通常我们使用拦截器绑定的组合类型绑定多个拦截器bean。例如,下面的声明将用于绑定TransactionInterceptor和SecurityInterceptor这2个拦截器到ShoppingCart.

@Secure(rolesAllowed="admin") @Transactional
public class ShoppingCart { ... }

然而,在非常复杂的情况下,一个拦截器本身可能指定拦截器绑定类型:

@Transactional @Secure @Interceptor
public class TransactionalSecureInterceptor { ... }
  • 1
  • 2

那么这个拦截器可以绑定到checkout() 方法,以下任何组合都可使用:

public class ShoppingCart {@Transactional @Secure public void checkout() { ... }
}
@Secure
public class ShoppingCart {@Transactional public void checkout() { ... }
}
@Transactional
public class ShoppingCart {@Secure public void checkout() { ... }
}
@Transactional @Secure
public class ShoppingCart {public void checkout() { ... }
}

6. Interceptor binding type inheritance(拦截器绑定类型继承)

Java语言支持注解的一个限制就是缺乏注解继承.注解应该重用内置已有的.就如同下面这段代码表达的意思

//实际没这写法
public @interface Action extends Transactional, Secure { ... }
  • 1
  • 2

幸运的是,CDI围绕Java没有的这个特性开展了一些工作.
我们会标注一个拦截器绑定类型,其有其他拦截器的绑定类型,(称为元注解)
表述起来有点费劲,就如同下面代码这样.

@Transactional @Secure
@InterceptorBinding
@Target(TYPE)
@Retention(RUNTIME)
public @interface Action { ... }

现在任何Bean绑定 Action这个注解 ,其实就是绑定到了@Transactional @Secure.(就是拦截器TransactionInterceptor和拦截器SecurityInterceptor). (甚至TransactionalSecureInterceptor,如果它存在.)

7.Use of @Interceptors(同时用多个拦截器)
这个注解@Interceptors是拦截器规范定义的,cdi是支持的<使用托管bean和EJB规范>.如下:

@Interceptors({TransactionInterceptor.class, SecurityInterceptor.class})
public class ShoppingCart {public void checkout() { ... }
}

但缺点也很明显,不推荐使用.缺点如下:

拦截器在代码中是硬编码.
拦截器在部署时不好更改.
拦截器命令是非全局的——它是在类级别由拦截器的顺序列出.
因此还是使用上面CDI的使用方式比较好.

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

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

相关文章

快速入门系列之 Rust 语言 GitChat连接

Rust 是一枚新星&#xff0c;兼顾开发效率和执行效率的语言。本文以实例为导向&#xff0c;讲解 Rust 这门语言&#xff0c;适合有一定其他面向对象语言基础的人员快速入门。 本文将讲解如下内容&#xff1a; - Hello World 从头起 - 各种类型各种算 - 各式流程来控制 - 数组…

java -jar maven项目打包提示.jar中没有主清单属性

mvn package java -jar target/java_bottom_level_learning-1.0-SNAPSHOT.jar这里报错了&#xff1a; target/java_bottom_level_learning-1.0-SNAPSHOT.jar中没有主清单属性 我们打开 jar 中的 /META_INF/ MANIFEST.MF缺少项目启动项&#xff0c;即没有Main-Class 怎么处理呢…

工作总结5:插槽的使用

什么是插槽&#xff1f; 插槽就是子组件中的提供给父组件使用的一个占位符&#xff0c;用<slot></slot> 表示&#xff0c;父组件可以在这个占位符中填充任何模板代码&#xff0c;如 HTML、组件等&#xff0c;填充的内容会替换子组件的<slot></slot>标…

pycharm 破解

亲测有效&#xff01; http://blog.lanyus.com/archives/174.html 备注&#xff1a; 注册码破解链接&#xff1a;http://idea.lanyus.com/ 将下载的jar包放入PyCharm.exe所在路径 如D:\pycharm\pycharm2017\PyCharm 2017.1.2\bin pycharm.exe.vmoptions 和pycharm64.exe.vmopti…

Java JVM 汇编代码入门 GitChat链接

为什么 new Integer(151)151&#xff1f;我来带你们一起学习下 JVM 汇编代码吧&#xff0c;窥探下神奇的 Java 中间语言到底什么样子的&#xff0c;能帮你更深入的理解 Java。 本文包含以下内容 工具介绍 JVM 汇编代码初见 汇编初步分析 局部变量生命周期 基础类型 大于 5 的…

Streaming 101

开宗明义&#xff01;本文根据Google Beam大神Tyler Akidau的系列文章《The world beyond batch: Streaming 101》(批处理之外的流式世界)整理而成&#xff0c; 主要讨论流式数据处理。在大数据领域&#xff0c;流式数据处理越发地重要了。原因有以下几点&#xff1a; 人们越来…

工作总结6:token问题

1.使用请求拦截器&#xff0c;拦截vue所有请求&#xff0c;增加token参数 使用倒数计时&#xff0c;假如token有效期60分钟&#xff0c;会在59分钟的时候去重新拿着refresh_Token&#xff0c;去请求新的token. 注意&#xff1a;如果一个账号允许多人登录使用&#xff0c;上述方…

从底层重学 Java 之四大整数 GitChat链接

从底层&#xff0c;从原理&#xff0c;我们来重学一次 Java。四大 Java 整数类 Byte、Short、Integer、Long 是我们比较常用的对象&#xff0c;他们的源码及实现是怎样的呢&#xff1f; 本系列秉承所有结论尽量从源码中来&#xff0c;没有源码的尽量标明出处。相关源码会附着在…

二重循环

一、回顾3种循环结构 1、while 语法 条件表达式的初始值&#xff1b; while(条件表达式){ 循环操作&#xff1b; 更改条件表达式的语句&#xff1b; } 特点&#xff1a;先判断&#xff0c;再执行&#xff0c;有可能一次循环都没有 适用的场合&#xff1a;循环次数未知 表现形式…

工作总结1:代码中漫花谷出现很多NBSP

代码复制的影响 手动删除 ctrl f 全部删除

winsw将命令部署为服务(比如springboot)

工具 https://github.com/winsw/winsw/releases 下载.netcore的exe就行&#xff0c;比如 https://github.com/winsw/winsw/releases/download/v2.9.0/WinSW.NETCore31.x64.exe PS&#xff1a;我为什么不下载net2那些版本&#xff0c;那些版本一看大小就是需要本地.netframewo…

GPU版的tensorflow在windows上的安装时的错误解决方案

1.用vs编译cuda的sample时会提示找不到”d3dx9.h”、”d3dx10.h”、”d3dx11.h”头文件的错误&#xff0c;如果没有安装这个插件&#xff0c;在TensorFlow里执行run方法时会导致电脑死机 解决方案;可从这里下载DXSDK_Jun10.exe。 2.import tensorflow as tf 时报 ImportError: …

ElementUI dialog嵌套蒙层遮挡问题

dialog嵌套会有蒙层遮挡问题&#xff0c;我们加两个属性解决他 <el-dialog :close-on-click-modal"false" title"选择图片" custom-class"imgSelectDialog" :visible.sync"imgSelectDialog" close"closeHandler" v-drag&…

excel转txt工具

有个任务需要读好多eccel&#xff0c;实际读起来并不方便&#xff0c;变手工把ecxcel转换成文本文档&#xff0c;心累。。。。于是闲暇写了个ecxcel转txt的小工具。主要是用的Spreadsheet::XLSX。 use strict;use warnings;use strict; use Spreadsheet::XLSX;die "Usage …

从底层重学 Java 之两大浮点类型 GitChat连接

从底层&#xff0c;从原理&#xff0c;我们来重学一次 Java。两大 Java 浮点类 Double、Float 是我们比较常用的对象&#xff0c;他们的源码及实现是怎样的呢&#xff1f; 本系列秉承所有结论尽量从源码中来&#xff0c;没有源码的尽量标明出处。相关源码会附着在文章中&#…

jquery点击完一个按钮,并且触发另一个按钮

$a.click(function(){ $b.trigger(click); }); 转载于:https://www.cnblogs.com/Neilisme/p/6890838.html

vue 中的动态传参和query传参

Vue router 如何传参 params、query 是什么&#xff1f; params&#xff1a;/router1/:id&#xff0c;这里的 id 叫做 params。例如/router1/123, /router1/789query&#xff1a;/router1?id123&#xff0c;这里的 id 叫做 query。例如/router1?id456 query 方式传参和接收…

element-ui如何进行调试

chrome中Sources打开webpack://域&#xff0c;找到.下的node_modules下的element-ui/lib目录下的element-ui.common.js。 所有的组件都被打包到了这里&#xff0c;怎么能快速找到组件呢&#xff1f;我们看下这个注释&#xff1a; // CONCATENATED MODULE: ./packages/checkbo…