注解(Annotation) 提供了一种安全的类似注释的机制,为我们在代码中添加信息提供了一种形式化得方法,使我们可以在稍后某个时刻方便的使用这些数据(通过解析注解来使用这些 数据),用来将任何的信息或者元数据与程序元素(类、方法、成员变量等)进行关联。其实就是更加直观更加明了的说明,这些说明信息与程序业务逻辑没有关 系,并且是供指定的工具或框架使用的。Annotation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的申明语句中。
Annotation其实是一种接口。通过java的反射机制相关的API来访问Annotation信息。相关类(框架或工具中的类)根据这些信息来决定如何使用该程序元素或改变它们的行为。Java语言解释器在工作时会忽略这些Annotation,因此在JVM中这些Annotation是“不起作用”的,只能通过配套的工具才能对这些Annotation类型的信息进行访问和处理。
Annotation和interface的异同:
1、 annotition的类型使用关键字@interface而不是interface。它继承了java.lang.annotition.Annotition接口,并非申明了一个interface。
2、 Annotation类型、方法定义是独特的、受限制的。Annotation类型的方法必须申明为无参数、无异常抛出的。这些方法定义了Annotation的成员:方法名称为了成员名,而方法返回值称为了成员的类型。而方法返回值必须为primitive类型、Class类型、枚举类型、Annotation类型或者由前面类型之一作为元素的一位数组。方法的后面可以使用default和一个默认数值来申明成员的默认值,null不能作为成员的默认值,这与我们在非Annotation类型中定义方法有很大不同。Annotation类型和他的方法不能使用Annotation类型的参数,成员不能是generic。只有返回值类型是Class的方法可以在Annotation类型中使用generic,因为此方法能够用类转换将各种类型转换为Class。
3、 Annotation类型又与接口有着近似之处。它们可以定义常量、静态成员类型(比如枚举类型定义)。Annotation类型也可以如接口一般被实现或者继承。
自定义注解
AOP思想下的自定义注解
java在我们要自定义注解的时候提供了它自己的自定义语法以及元注解,元注解(负责注解其他注解): Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:
1.@Target,
2.@Retention,
3.@Documented,
4.@Inherited
这些类型和它们所支持的类在java.lang.annotation包中可以找到。
1.@Target:用户描述注解的作用范围
取值(ElementType)有:
1.CONSTRUCTOR:用于描述构造器
2.FIELD:用于描述域
3.LOCAL_VARIABLE:用于描述局部变量
4.METHOD:用于描述方法
5.PACKAGE:用于描述包
6.PARAMETER:用于描述参数
7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
2.@Retention:表示需要在什么级别保存该注释信息
取值(RetentionPoicy)有:
1.SOURCE:在源文件中有效(即源文件保留)
2.CLASS:在class文件中有效(即class保留)
3.RUNTIME:在运行时有效(即运行时保留)(常用)
3.@Documented:Documented是一个标记注解
4.@Inherited :用于声明一个注解;
自定义注解语法:
public @interface 注解名 {定义体}
/**
* @author LittleOrange
* @version 2018年12月10日 下午4:59:15
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Component
public @interface SysLog {
String value() default "";
}
注意:
1.只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为default默认类型
2.这里的参数成员可以是八种基本数据类型,和String,Enum,Class,annotations等数据类型,以及这一些类型的数组,这里是String
3.最好把参数名称设为"value()" 后面为默认的值。
/**
* 系统日志,切面处理类
* @author LittleOrange
* @version 2018年12月10日 下午4:59:15
*/
@Aspect
@Component
public class SysLogAspect {
@Autowired
private LogService logService;
//这个里面需要写自定义注解的全限定名(包名+类名)
@Pointcut("@annotation(com.stm.controller.base.annotation.SysLog)")
public void logPointCut() {
}
@Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
long beginTime = System.currentTimeMillis();
//执行方法
Object result = point.proceed();
//执行时长(毫秒)
long time = System.currentTimeMillis() - beginTime;
//保存日志
saveSysLog(point, time);
return result;
}
/**
* 保存系统日志
* @param joinPoint
* @param time
*/
private void saveSysLog(ProceedingJoinPoint joinPoint, long time) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
/*SysLog syslog = method.getAnnotation(SysLog.class);
if(syslog != null){
//注解上的描述
System.out.println(syslog.value());
}*/
/*SysLog sysLog = new ();*/
//获取request请求
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = attr.getRequest();
UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
Browser browser = userAgent.getBrowser();
String browsers = browser+"";
System.out.println("浏览器 "+browsers);
OperatingSystem os = userAgent.getOperatingSystem();
String oss = os+"";
System.out.println("os "+oss);
String ip = "";
try {
ip = InetAddress.getLocalHost().getHostAddress(); //ip 地址
} catch (UnknownHostException e) {
e.printStackTrace();
}
System.out.println("ip "+ip);
Date date = new Date();
System.out.println(date);
com.stm.pojo.system.SysLog sysLog = new com.stm.pojo.system.SysLog();
SysLog syslog = method.getAnnotation(SysLog.class);
HttpSession session = request.getSession();
String userName = (String) session.getAttribute("userName");
if(syslog != null){
//注解上的描述
sysLog.setLogIp(ip);
sysLog.setLogRemark(syslog.value());
sysLog.setLogTime(date);
sysLog.setUserName(userName);
sysLog.setLogSystem(oss);
sysLog.setLogBrowser(browsers);
}
//请求的方法名
String className = joinPoint.getTarget().getClass().getName();
String methodName = signature.getName();
//sysLog.setMethod(className + "." + methodName + "()");
logService.insert(sysLog);
}
}
注解本身不做任何事情,只是像xml文件一样起到配置作用。注解代表的是某种业务意义,注解背后处理器的工作原理如上所示:首先解析所有属性,判断属性上是否存在指定注解,如果存在则根据搜索规则取得bean,然后利用反射原理注入。如果标注在字段上面,也可以通过字段的反射技术取得注解,根据搜索规则取得bean,然后利用反射技术注入。