奉贤专业网站建设,移动4G网站建设,门户网站内容,网站建设 新手从一、注解及其原理 1.注解的基本概念
注解#xff0c;可以看作是对 一个类/方法的一个扩展的模版#xff0c;每个类/方法按照注解类中的规则#xff0c;来为类/方法注解不同的参数#xff0c;在用到的地方可以得到不同的类/方法中注解的各种参数与值。 从JDK5开始#xff…一、注解及其原理 1.注解的基本概念
注解可以看作是对 一个类/方法的一个扩展的模版每个类/方法按照注解类中的规则来为类/方法注解不同的参数在用到的地方可以得到不同的类/方法中注解的各种参数与值。 从JDK5开始Java增加了对元数据描述数据属性的信息的支持。其实说白就是代码里的特殊标志这些标志可以在编译、类加载和运行时被读取并执行相应的处理。通过注解开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息。
2.标准注解与元注解
2.1.标准注解
2.1.1.Override
定义在 java.lang.Override中此注解只能作用于方法表示一个方法声明打算重写超类中的另一个方法声明简单来说就是子类在重写父类方法的时候可以加上这个注解。默认情况下子类重写的方法会自动覆盖父类的方法但经验告诉我们必须显式地在子类重写父类的方法上添加Override注解来检查并标记子类是否重写了父类的方法。
2.1.2.Deprecated
定义在java.lang.Deprecated中此注解可以作用于方法、属性 和类等等表示不建议程序员使用被Deprecated所作用的对象通常是因为它很危险或者存在更好的选择即此对象已经过时不推荐使用。例如
作用在方法上 作用在类上
2.1.3.SuppressWarnings
定义在 java.lang.SuppressWarnings 中用来抑制编译时的警告信息与前两个注释有所不同你需要添加一个参数才能正确使用这些参数都是已经定义好了的, 我们选择性的使用就好了一般我们使用SuppressWarnings(“all”)。
2.2.元注解
除了 Java 中为我们定义好的注解我们还可以通过元注解来自定义注解 Java定义了4个标准的元注解meta-annotation用来定义和描述其他注解自定义注解所以也称为元数据注解。
2.2.1.Target
用来描述注解的作用对象即注解可以使用在什么地方在定义注解的时候使用该注解可以清晰地知道它的使用范围它的取值范围被定义在了一个枚举类中常见的枚举值包括
ElemenetType.CONSTRUCTOR 构造器声明 ElemenetType.FIELD 域声明包括 enum 实例ElemenetType.LOCAL_VARIABLE 局部变量声明ElemenetType.METHOD 方法声明ElemenetType.PACKAGE 包声明ElemenetType.PARAMETER 参数声明ElemenetType.TYPE 类接口包括注解类型或enum声明
2.2.2.Retention
用来描述在什么级别保存该注解信息。可选的参数值在枚举类型 RetentionPolicy中包括
RetentionPolicy.SOURCE 注解将被编译器丢弃RetentionPolicy.CLASS 注解在class文件中可用但会被VM丢弃RetentionPolicy.RUNTIME VM将在运行期也保留注解因此可以通过反射工具读取注解的信息。
2.2.3.Documented
将此注解包含在javadoc中它代表着此注解会被javadoc工具提取成文档。在doc文档中的内容会因为此注解的信息内容不同而不同。相当与seeparam等。
2.2.4.Inherited
表示允许子类继承父类中的注解。
3.自定义注解
3.1.通过元注解定义注解
通过元注解我们可以定义新的注解。长久以来注解被视为一种轻量级的配置化技术方案与XML相比注解更加简单、便捷但注解一般应用于比较简单的参数配置而对于复杂的参数就必须借助XML这个工具了。
3.1.1.定义注解及属性声明
使用interface关键字来定义新的注解。例如 注解和类一样也可以声明自己的属性用来对注解自身进行描述。这样原来写在配置文件中的信息就可以通过注解的属性进行描述。 1)定义注解的必录属性String name()在使用注解时通过namexxx来设置属性name的值若没有设置属性name的值系统会提示编译异常。 2)定义注解属性的默认值String name() default “test”在使用注解时若没有设置属性name的值系统会自动将注解的name属性设置为默认值test。 3)特殊属性value如果注解Query中只定义了一个名称为value的必录属性那么使用注解时可以省略value如Query (“xxx”)。
3.1.2.定义不包含属性的注解
这类注解内部不存在任何属性因此仅仅是起到一个标记的作用与标记接口类似。下面是一个不包含属性的自定义注解示例
3.1.3.定义包含属性的注解
注解还可以定义自己的属性这些属性可以用来存储一些关键、特征信息以便程序通过当前注解的属性存储的信息来处理相应的业务逻辑。下面是一个包含属性的自定义注解示例
3.1.3.1.注解属性支持的数据类型
注解的属性与类的属性除了声明方式存在差异外还体现在所支持的数据类型。注解属性支持的数据类型包含以下几种
所有基本数据类型字符串类型String枚举类型enum注解类型Annotation以上数据类型的数组类型
例如 注意如果你使用了其他数据类型就会提示编译异常。
3.2.注解的使用
在上文中我们定义了方法注解因此可以作为方法级的轻量级配置使用具体使用方式如下所示
二、Spring注解原理剖析
Spring注解是自定义注解在实际开发中的最佳实践之一一般而言我接触到的Spring注解——Controller、Service和Autowired等注解都是运行时注解因此底层都是基于Java反射实现的。下面我们通过一个实际案例来深入理解Spring框架中注解的底层实现原理。
1.自定义自动注入注解思路点拨
思路点拨由于Service类应用于Controller类中因此可以通过切面拦截Controller类而切面无法拦截类上的注解只能拦截方法上的注解拦截到目标类的所有方法后就遍历Controller类的所有属性并判断属性上是否标记了AutoInjected注解再通过反射将实现类的实例注入到该属性中。
2.自定义AutoInjected注解
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;Target(ElementType.FIELD)
Retention(RetentionPolicy.RUNTIME)
Documented
public interface AutoInjected {
}3.创建AutoInjectedAspect切面
import com.zh.test.annotation.AutoInjected;
import com.zh.test.system.utils.ApplicationUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RestController;
import java.lang.reflect.Field;Aspect
Component
public class AutoInjectedAcpect {Pointcut(execution(* com.zh.test..*.controller..*.*(..)))public void beforeDoPointcut() {}Before(beforeDoPointcut())public void beforeDo(JoinPoint joinPoint) {Object target joinPoint.getTarget();// 判断目标类是否标记了RestController或Controller注解RestController restController AnnotationUtils.findAnnotation(target.getClass(), RestController.class);if(restController null) {Controller controller AnnotationUtils.findAnnotation(target.getClass(), Controller.class);if(controller null) {return;}}Field[] fields target.getClass().getDeclaredFields();for(Field field : fields) {// 获取属性上的注解AutoInjected autoInjected field.getAnnotation(AutoInjected.class);// 如果为空说明该属性上没有标记AutoInjected注解不予处理if(autoInjected null) {continue;}Class? fieldType field.getType();// 获取属性对应接口类型的实现类的实例Object bean ApplicationUtil.getBean(fieldType);try {field.setAccessible(true);// 将属性对应接口类型的实现类的实例属注入到属性中field.set(target, bean);} catch (IllegalAccessException e) {throw new RuntimeException(e.getMessage());}}}
}4.AutoInjected注解的应用
import com.zh.test.annotation.AutoInjected;
import com.zh.test.system.entity.SysPageMeta;
import com.zh.test.system.service.IDemoService;
import com.zh.test.system.service.IMetaService;
import com.zh.test.system.service.impl.DemoServiceImpl;
import com.zh.test.system.utils.ApplicationUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.lang.reflect.Field;
import java.util.Map;RequestMapping(/demo)
RestController
public class DemoController {AutoInjectedprivate IDemoService service;AutoInjectedprivate IMetaService metaService;GetMapping(/queryByPage)public MapString, Object queryByPage() {MapString, Object result service.queryByPage();return result;}PostMappingpublic Boolean addMetadata() {boolean result metaService.addMetadata(new SysPageMeta());return result;}}三、注解的实际应用
在第一章中我们自定义的注解都是运行时注解因此可以通过反射工具获取注解信息。不同的作用对象获取注解的方式也不相同下面我们举例说明。
1.通过切面实现自定义方法注解
当注解定义在类或方法上时可以通过切面拦截并获取注解实例。在SpringBoot项目中如果要使用切面就必须引入以下的jar包依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId
/dependency可以通过注解Aspect和Component来定义一个切面类 具体示例如下
Aspect
Component
public class QueryAspect {Before(annotation(query))public void beforeQuery(JoinPoint joinPoint, Query query) {// 数据库String dbName query.dbName();// 表名String tableName query.tableName();// 是否分页boolean paginate query.paginate();// 字段信息Column[] columns query.columns();System.out.println(dbName: dbName);System.out.println(tableName: tableName);System.out.println(paginate: paginate);System.out.println(columns: Arrays.toString(columns));}
}注意当切面的切点表达式为annotation(xxx)时目标注解必须作用于目标对象的方法上否则切面将无法拦截到目标注解
2.通过ConstraintValidator校验器自定义方法参数注解
当注解定义在方法参数上时无法通过切面拦截并获取注解实例此时就必须借助ConstraintValidator校验器来获取注解信息。示例如下
引入hibernate-validator.jar包依赖
dependencygroupIdorg.hibernate.validator/groupIdartifactIdhibernate-validator/artifactIdversion6.0.0.Final/version
/dependency定义用于辅助校验的注解
例子如下
// 注解作用对象为类和方法参数
Target({ElementType.TYPE, ElementType.PARAMETER})
// 运行时类型的注解可通过反射工具获取当前注解实例
Retention(RetentionPolicy.RUNTIME)
Documented
public interface ExtCheck {String message() default 非法扩展字段;Class?[] groups() default {};Class? extends Payload[] payload() default {};
}注意辅助校验的注解必须至少包含message、groups和payload三个最基本的成员属性否则将抛出运行时异常。
实现ConstraintValidator接口 例子如下 在ExtCheck注解上添加上述实现的ConstraintValidator校验器 例子如下 定义全局异常处理器 例子如下
import com.zh.test.exception.ExtException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;/*** 全局异常处理器*/
RestControllerAdvice
public class GlobalExceptionHandler {ExceptionHandler(ExtException.class)public String handleAccessDeniedException(ExtException e, HttpServletRequest request) {return e.getMessage();}
}public class ExtException extends RuntimeException {public ExtException() {super();}public ExtException(String message) {super(message);}}在Controller层的类或方法参数前添加Validated必须和ExtCheck注解 文章转载自: http://www.morning.cwpny.cn.gov.cn.cwpny.cn http://www.morning.smygl.cn.gov.cn.smygl.cn http://www.morning.tllws.cn.gov.cn.tllws.cn http://www.morning.ktyww.cn.gov.cn.ktyww.cn http://www.morning.hmnhp.cn.gov.cn.hmnhp.cn http://www.morning.bfcrp.cn.gov.cn.bfcrp.cn http://www.morning.npxcc.cn.gov.cn.npxcc.cn http://www.morning.gslz.com.cn.gov.cn.gslz.com.cn http://www.morning.bpwdc.cn.gov.cn.bpwdc.cn http://www.morning.snbq.cn.gov.cn.snbq.cn http://www.morning.wfyzs.cn.gov.cn.wfyzs.cn http://www.morning.lqzhj.cn.gov.cn.lqzhj.cn http://www.morning.ylzdx.cn.gov.cn.ylzdx.cn http://www.morning.kmkpm.cn.gov.cn.kmkpm.cn http://www.morning.jhqcr.cn.gov.cn.jhqcr.cn http://www.morning.wrlxt.cn.gov.cn.wrlxt.cn http://www.morning.zxfdq.cn.gov.cn.zxfdq.cn http://www.morning.mcwgn.cn.gov.cn.mcwgn.cn http://www.morning.ztqj.cn.gov.cn.ztqj.cn http://www.morning.rbbzn.cn.gov.cn.rbbzn.cn http://www.morning.grwgw.cn.gov.cn.grwgw.cn http://www.morning.pcjw.cn.gov.cn.pcjw.cn http://www.morning.zstry.cn.gov.cn.zstry.cn http://www.morning.bwygy.cn.gov.cn.bwygy.cn http://www.morning.dgpxp.cn.gov.cn.dgpxp.cn http://www.morning.cwqpl.cn.gov.cn.cwqpl.cn http://www.morning.rfyff.cn.gov.cn.rfyff.cn http://www.morning.fbdkb.cn.gov.cn.fbdkb.cn http://www.morning.nfzzf.cn.gov.cn.nfzzf.cn http://www.morning.pmhln.cn.gov.cn.pmhln.cn http://www.morning.lynkz.cn.gov.cn.lynkz.cn http://www.morning.jqwpw.cn.gov.cn.jqwpw.cn http://www.morning.rfxg.cn.gov.cn.rfxg.cn http://www.morning.zhengdaotang.cn.gov.cn.zhengdaotang.cn http://www.morning.ynlpy.cn.gov.cn.ynlpy.cn http://www.morning.xprzq.cn.gov.cn.xprzq.cn http://www.morning.kmcfw.cn.gov.cn.kmcfw.cn http://www.morning.grxsc.cn.gov.cn.grxsc.cn http://www.morning.ygrdb.cn.gov.cn.ygrdb.cn http://www.morning.ptmgq.cn.gov.cn.ptmgq.cn http://www.morning.zczkm.cn.gov.cn.zczkm.cn http://www.morning.xirfr.cn.gov.cn.xirfr.cn http://www.morning.lbywt.cn.gov.cn.lbywt.cn http://www.morning.nyqzz.cn.gov.cn.nyqzz.cn http://www.morning.cfocyfa.cn.gov.cn.cfocyfa.cn http://www.morning.ndcjq.cn.gov.cn.ndcjq.cn http://www.morning.yrrnx.cn.gov.cn.yrrnx.cn http://www.morning.wdhhz.cn.gov.cn.wdhhz.cn http://www.morning.nrqnj.cn.gov.cn.nrqnj.cn http://www.morning.wjxtq.cn.gov.cn.wjxtq.cn http://www.morning.rhpgk.cn.gov.cn.rhpgk.cn http://www.morning.qmbtn.cn.gov.cn.qmbtn.cn http://www.morning.kkjhj.cn.gov.cn.kkjhj.cn http://www.morning.ggjlm.cn.gov.cn.ggjlm.cn http://www.morning.kxbdm.cn.gov.cn.kxbdm.cn http://www.morning.cwrpd.cn.gov.cn.cwrpd.cn http://www.morning.mhbcy.cn.gov.cn.mhbcy.cn http://www.morning.tbjtm.cn.gov.cn.tbjtm.cn http://www.morning.kjdxh.cn.gov.cn.kjdxh.cn http://www.morning.mfrb.cn.gov.cn.mfrb.cn http://www.morning.rwfj.cn.gov.cn.rwfj.cn http://www.morning.gwmjy.cn.gov.cn.gwmjy.cn http://www.morning.wdhlc.cn.gov.cn.wdhlc.cn http://www.morning.xylxm.cn.gov.cn.xylxm.cn http://www.morning.fncgw.cn.gov.cn.fncgw.cn http://www.morning.rbkdg.cn.gov.cn.rbkdg.cn http://www.morning.wnzgm.cn.gov.cn.wnzgm.cn http://www.morning.hmfxl.cn.gov.cn.hmfxl.cn http://www.morning.hrkth.cn.gov.cn.hrkth.cn http://www.morning.fpryg.cn.gov.cn.fpryg.cn http://www.morning.pflpb.cn.gov.cn.pflpb.cn http://www.morning.rbzd.cn.gov.cn.rbzd.cn http://www.morning.lqchz.cn.gov.cn.lqchz.cn http://www.morning.rgyts.cn.gov.cn.rgyts.cn http://www.morning.rkwlg.cn.gov.cn.rkwlg.cn http://www.morning.sypby.cn.gov.cn.sypby.cn http://www.morning.gbsfs.com.gov.cn.gbsfs.com http://www.morning.pjtnk.cn.gov.cn.pjtnk.cn http://www.morning.pzbjy.cn.gov.cn.pzbjy.cn http://www.morning.hwlmy.cn.gov.cn.hwlmy.cn