一、java自定义注解相关知识

  注解这东西是java语言本身就带有的功能特点,于struts,hibernate,spring这三个框架无关。使用得当特别方便。基于注解的xml文件配置方式也受到人们的推崇,其具有方便扩展,直观易懂,对现有的代码没有破坏性等等诸多优点。JAVA注解使用起来也比较简单。下面就简单讲一下使用自定义注解的方法。

  (第一部分转自http://www.open-open.com/lib/view/open1353144218545.html)

  1.定义注解

  

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Description {
String value();
}

  其中的@interface是一个关键字,在设计annotations的时候必须把一个类型定义为@interface,而不能用class或interface关键字。所有的注解类都隐式继承于 java.lang.annotation.Annotation,注解不允许显式继承于其他的接口。

  一个注解可以拥有多个成员,成员声明和接口方法声明类似,这里,我们仅定义了一个成员,成员的声明有以下几点限制:

  a)   成员以无入参无抛出异常的方式声明,如boolean value(String str)、boolean value() throws Exception等方式是非法的;

  b)   可以通过default为成员指定一个默认值,如String level() default "LOW_LEVEL"、int high() default 2是合法的,当然也可以不指定默认值;

  c)   成员类型是受限的,合法的类型包括原始类型及其封装类、String、Class、enums、注解类型,以及上述类型的数组类型。如ForumService value()、List foo()是非法的。

  d)   如果注解只有一个成员,则成员名必须取名为value(),在使用时可以忽略成员名和赋值号(=),如@Description("使用注解的实例")。注解类拥有多个成员时,如果仅对value成员进行赋值则也可不使用赋值号,如果同时对多个成员进行赋值,则必须使用赋值号,如@DeclareParents (value = "NaiveWaiter", defaultImpl = SmartSeller.class)。

  e)   注解类可以没有成员,没有成员的注解称为标识注解,解释程序以标识注解存在与否进行相应的处理;

  注解定义包含四个元注解,分别为@Target,@Retention,@Documented,@Inherited。各元注解的作用如下:

  

  @Target

    表示该注解用于什么地方,可能的 ElemenetType 参数包括:

  Ø  ElemenetType.CONSTRUCTOR 构造器声明。

  Ø  ElemenetType.FIELD 域声明(包括 enum 实例)。

  Ø  ElemenetType.LOCAL_VARIABLE 局部变量声明。

  Ø  ElemenetType.METHOD 方法声明。

  Ø  ElemenetType.PACKAGE 包声明。

  Ø  ElemenetType.PARAMETER 参数声明。

  Ø  ElemenetType.TYPE 类,接口(包括注解类型)或enum声明。

  @Retention

    表示在什么级别保存该注解信息。可选的 RetentionPolicy 参数包括:

  Ø  RetentionPolicy.SOURCE 注解将被编译器丢弃。

  Ø  RetentionPolicy.CLASS 注解在class文件中可用,但会被VM丢弃。

  Ø  RetentionPolicy.RUNTIME VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息。

举一个例子,如@Override里面的Retention设为SOURCE,编译成功了就不要这一些检查的信息,相反,@Deprecated里面的Retention设为RUNTIME,表示除了在编译时会警告我们使用了哪个被 Deprecated的方法,在执行的时候也可以查出该方法是否被Deprecated。

  @Documented

    将此注解包含在 javadoc 中。(详细度娘)

  @Inherited

    允许子类继承父类中的注解。(详细度娘)

  2.使用注解

  

@Description(value="zhujie")
public class TestAnnotation { }

  

  使用注解的语法:@<注解名>(<成员名1>=<成员值1>,<成员名1>=<成员值1>,...)

  如果成员是数组类型,可以通过{}进行赋值,如boolean数组的成员可以设置为{true,false,true}。下面是几个注解标注的例子:

  1)   多成员的注解

  @AnnoExample(id= 2868724, synopsis = "Enable time-travel", engineer = "Mr. Peabody")

  2)   一个成员的注解,成员名为value

  可以省略成员名和赋值符号:@Copyright("Right Reserved")

  @Copyright("2011 bookegou.com All Right Reserved")

  3)   无成员的注解

  @Override

  4)   成员为字符串数组的注解

  @SuppressWarnings(value={"unchecked","fallthrough"})

  @SuppressWarnings(value={"unchecked","fallthrough"})

  5)   成员为注解数组类型的注解

  @Reviews({@Review(grade=Review.Grade.EXCELLENT,reviewer="df"),

  @Review(grade=Review.Grade.UNSATISFACTORY,reviewer="eg",

  comment="This method needs an @Override annotation")})

  @Reviews({@Review(grade=Review.Grade.EXCELLENT,reviewer="df"),

@Review(grade=Review.Grade.UNSATISFACTORY,reviewer="eg",

comment="This method needs an @Override annotation")})

  @Reviews注解拥有一个@Review注解数组类型的成员,@Review注解类型有三个成员,其中reviewer、comment都是String类型,但comment有默认值,grade是枚举类型的成员。

  3.解析注解/获得注解属性

public class ParseAnnotation {
public static void main(String[] args) throws Exception{
final Class cls = Class.forName("com.annotation.TestAnnotation");
final Method[] method = cls.getMethods();
// 判断是否有指定注解类型的注解
if(cls.isAnnotationPresent(Description.class)) {
// 根据注解类型返回指定类型的注解
Description des = (Description)cls.getAnnotation(Description.class);
System.out.println("注解描述:" + des.value());
}
}
}

  输出结果如下:注解描述:zhujie

  注解不能直接干扰程序代码的运行,无论增加或删除注解,代码都能够正常运行。Java语言解释器会忽略这些注解,而由第三方工具负责对注解进行处理。第三方工具可以利用代码中的注解间接控制程序代码的运行,它们通过Java反射机制读取注解的信息,并根据这些信息更改目标程序的逻辑,而这正是Spring AOP对@AspectJ提供支持所采取的方法。

  

  二、SSH框架下,拦截器中无法获得java注解属性值的问题

  上面的实例并不是在java web环境下运行,而我是在ssh环境下,想使用自定义注解。在拦截器中,我通过Class actionClass=invocation.getProxy().getAction().getClass()获得action的类,并通过以下代码获得目标action头上的注解属性信息。

if (actionClass.isAnnotationPresent(LogAnnotation.class)) {
LogAnnotation actionAnnotation = (LogAnnotation) actionClass.getAnnotation(LogAnnotation.class);
}

  其中,自定义注解如下:

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType; @Target( {ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface LogAnnotation {
String objectType();
}

  目标action方法如下:

@LogAnnotation (objectType = "LogAction")
public class LogAction extends BaseAction {
@LogAnnotation (objectType = "LogView")
public String view() {}
}

  可是,我在调试时actionClass.isAnnotationPresent(LogAnnotation.class)怎么也不能判断为真,获得actionAnnotation为null。

  我将actionClass直接写为com.action.log.LogAction.class.isAnnotationPresent(LogAnnotation.class)是可以进入if语句,或得到actionAnnotation并获得由actionAnnotation.objectType()获得注解属性值。

  断点调试时,actionClass为class com.action.log.LogAction$$EnhancerByCGLIB$$ea0373e6,可以发现后面多了一串东西$$EnhancerByCGLIB$$ea0373e6,刚人门,才疏学浅尚不知道这什么,可能是实现拦截器的cglib,具体原理我还没深究。查了很多资料,http://tieba.baidu.com/p/1782928180,http://stackoverflow.com/questions/15174599/classisannotationpresent-not-working。这个问答感觉和我这个遇到的有点点相似,但好像又不一样。找了很多资料,很久都不知道怎么解决。后来,我想,如果先把类转成string,再通过字符串截取把那个尾缀去掉,再转成类会不会就ok了?可能这个办法好像不官方,但也算一个方法了。

  

        Class actionTempClass=invocation.getProxy().getAction().getClass();
int i=actionTempClass.toString().indexOf("$$EnhancerByCGLIB");
String actionString =actionTempClass.toString().substring(6, i);
Class actionClass=Class.forName(actionString);
// 如果设置了注解则读取注解的内容,如果没有设置注解则记录登录的class名
if (actionClass.isAnnotationPresent(LogAnnotation.class)) {
LogAnnotation actionAnnotation = (LogAnnotation) actionClass.getAnnotation(LogAnnotation.class);
String objectTypeString =actionAnnotation.objectType();
}

  经测试这个方案是可行的。同理action中的方法也可以通过此方法获得注解属性值。

  

        Class actionTempClass=invocation.getProxy().getAction().getClass();
int i=actionTempClass.toString().indexOf("$$EnhancerByCGLIB");
String actionString =actionTempClass.toString().substring(6, i);
Class actionClass=Class.forName(actionString);
String methodName = invocation.getProxy().getMethod();
Method method = actionClass.getMethod(methodName, null);//
// Method method = invocation.getAction().getClass().getMethod(methodName, null);
// 如果设置了注解则读取注解的内容,如果没有设置注解则记录登录的method名
if (method.isAnnotationPresent(LogAnnotation.class)) {
LogAnnotation methodAnnotation = (LogAnnotation) method.getAnnotation(LogAnnotation.class);
}

   具体的导致原因还需要深究,敬请期待。

java自定义注解知识实例及SSH框架下,拦截器中无法获得java注解属性值的问题的更多相关文章

  1. ssh框架里拦截器的权限验证基本思路【转】

    相关表 序号 表性质 表名 字段 字段 字段 字段 字段 1 基表 用户表 id 帐号 密码     2 基表 角色表 id 角色名       3 基表 权限表 id 权限名 请求路径     4 ...

  2. java ssh 框架下 利用junit4 spring-test进行单元测试

    ssh框架下  由于bean实列 都交给spring 管理,要做单元测试就比较苦难,junit4 引入注解方便很多: 1. 加入依赖包 使用Spring的测试框架需要加入以下依赖包: JUnit 4 ...

  3. SSH框架下单元测试的实现

    SSH框架下单元测试的实现 实现的功能 实现了部门的增删改查 对Action进行了单元测试 对Service 进行了单元测试,通过mock的方式实现. 实现的步骤 一.对Action层的单元测试实现 ...

  4. SSH框架下的多表增删改查

    下载地址:SSH框架下的多表增删改查 点击进入码云Git下载 点击进入CSDN下载 项目结构: 项目代码就不全部贴出来了,只贴下核心代码.需要项目的自己可以去下载. package com.atgui ...

  5. SpringMVC入门一:基础知识(依赖、注解、文件上传/下载、拦截器、异常处理等)

    为了使Spring可插入MVC架构,SpringFrameWork在Spring基础上开发SpringMVC框架,从而使用Spring进行WEB开发时可以选择使用Spring的SpringMVC框架作 ...

  6. SSH框架下的表单重复提交

    前几天做了一个功能,是在某个操作后,刷新父页面的,刷新时弹出了下面图的框: 网上查了之后发现这个框是表单重复提交时出现的.分析后发现,这个页面的上一个动作是form submit(在ssh框架下),这 ...

  7. 为什么你写的拦截器注入不了 Java bean?

    一.如何实现拦截器 在Spring Boot项目中,拦截器经常被用来做登陆验证,日志记录等操作.拦截器是Spring提供的,所以可以将拦截器注成bean,由IOC容器来管理.实现拦截器的方式很简单,主 ...

  8. 针对shiro框架authc拦截器认证成功后跳转到根目录,而非指定路径问题

    一.针对shiro框架authc拦截器认证成功后跳转到根目录,而非指定路径问题 首先,我们先来了解一下authc登录拦截器工作原理 authc拦截器有2个作用: 1>登录认证     请求进来时 ...

  9. PhoneGap或者Cordova框架下实现Html5中JS调用Android原生代码

    PhoneGap或者Cordova框架下实现Html5中JS调用Android原生代码 看看新闻网>看引擎>开源产品 0人收藏此文章, 发表于8小时前(2013-09-06 00:39) ...

随机推荐

  1. 应用activeMQ消息中间件同步索引库

    mq是一个消息服务器: 安装包内置了tomcat,直接登录访问,登录:http://ip:8161/admin/    (相当于dubbo的moniter监控中心) admin admin传统串行化, ...

  2. 数据库的SQL优化

    1.对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. (因为在条件查询条件添加索引,会直接被检索到列,会非常的快速) 2.应尽量避免在 wher ...

  3. Servlet小总结

    Servlet Servlet(服务器端小程序)是使用Java语言编写的服务器端程序,像JSP一样,生成动态的Web页.Servlet主要运行在服务器端,并由服务器调用执行. Servlet处理的基本 ...

  4. 小白的Python之路 day4 生成器

    一.列表生成式  看下面例子: 列表生成式的作用:主要是让代码更简洁(还有装X的效果) 二.生成器 通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包 ...

  5. [Mean of range in array]

    Given an array of n integers and q queries. Write a program to print floor value of mean in range l  ...

  6. 微信JS-SDK使用步骤(以微信扫一扫为例)

    概述: 微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包. 通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照.选图.语音.位置等手机系统的能力,同时可以直接使用 ...

  7. 序列化之对象,字符串,byte数组,XML之间的转换(一)

    工作一年多了,越来越感到自己不能这样一直下去,在最好的青春里面却已经死了.被时间消磨了意志,被工作杀死了精神.我想,我只要活着,我就要去不断的要求自己,不断的去追求更高的山峰. 放眼四周,有趣的灵魂越 ...

  8. js 停止事件冒泡 阻止浏览器的默认行为(阻止a标签跳转 )

    在前端开发工作中,由于浏览器兼容性等问题,我们会经常用到"停止事件冒泡"和"阻止浏览器默认行为". 1..停止事件冒泡 JavaScript代码 //如果提供了 ...

  9. K:java中序列化的两种方式—Serializable或Externalizable

    在java中,对一个对象进行序列化操作,其有如下两种方式: 第一种: 通过实现java.io.Serializable接口,该接口是一个标志接口,其没有任何抽象方法需要进行重写,实现了Serializ ...

  10. 从JVM字节码执行看重载和重写

    Java 重写(Override)与重载(Overload) 重写(Override) 重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变.即外壳不变,核心重写! 重写的 ...