1 注解
1.1 要点
元注解:注解的注解
@Retention(生命范围:源代码,class,runtime)、@Inherited、@Documented、@Target(作用范围,方法,属性,构造方法等)。
@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-------将在运行期也保留注释,因此可以通过反射机制读取注解的信息。
@Documented 将此注解包含在 javadoc 中 ,它代表着此注解会被javadoc工具提取成文档。在doc文档中的内容会因为此注解的信息内容不同而不同。相当与@see,@param 等。
@Inherited 允许子类继承父类中的注解。
1.2 使用
自定义注解:
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Description {
String desc();
String author();
int age() default 18;
}
String desc();虽然它很类似于接口里面的方法,其实它在注解里面只是一个成员变量(成员以无参无异常的方式声明),int age() default 18;(成员变量可以用default指定一个默认值的)
①.成员类型是受限制的,合法的类型包括基本的数据类型以及String,Class,Annotation,Enumeration等。
②.如果注解只有一个成员,则成员名必须取名为value(),在使用时可以忽略成员名和赋值号(=)。
③.注解类可以没有成员,没有成员的注解称为标识注解。
使用自定义注解:
@<注解名>(<成员名1>=<成员值1>,<成员名1>=<成员值1>,…)
@Description(desc="i am Color",author="boy",age=18)
public String Color() {
return "red";
}
解析注解:
public class ParseAnn {
public static void main(String[] args) {
try {
// 使用类加载器加载类
Class c = Class.forName("com.test.Child");
// 类上面的注解
boolean isExist = c.isAnnotationPresent(Description.class);
// 上面的这个方法是用这个类来判断这个类是否存在Description这样的一个注解
if (isExist) {
// 拿到注解实例,解析类上面的注解
Description d = (Description) c.getAnnotation(Description.class);
System.out.println(d.value());
}
//方法上的注解
//获取所有的方法
Method[] ms = c.getMethods();
// 遍历所有的方法
for (Method m : ms) {
boolean isExist1 = m.isAnnotationPresent(Description.class);
if (isExist1) {
Description d1=m.getAnnotation(Description.class);
System.out.println(d1.value());
}
}
//另一种解析方法
for (Method m : ms) {
//拿到方法上的所有的注解
Annotation[] as=m.getAnnotations();
for (Annotation a : as) {
//用二元操作符判断a是否是Description的实例
if (a instanceof Description) {
Description d=(Description) a;
System.out.println(d.value());
}
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
基于@AspectJ的AOP
定义一个将使用切面的类:
public class NaiveWaiter implements Waiter {
@Override
public void greetTo(String clientName) {
System.out.println("greeting to "+ clientName +"...");
}
@Override
public void serveTo(String clientName) {
System.out.println("serving to "+ clientName +"...");
}
}
使用@AspectJ定义一个切面
@Aspect
public class PreGreetingAspect {
@Before("execution(* greetTo(..))")
public void beforeGreeting(){
System.out.println("how are you");
}
//带参数的增强方法
/*@Before("execution(* greetTo(..))&&args(name)")
public void beforeGreeting(JoinPoint jp,String name){
System.out.println("how are you "+jp.getArgs()[0]);
System.out.println("how are you "+name);
}*/
//使用命名切点
/*@After("com.smart.aspect.pointcut.TestNamePointcut.serveToPointcut()")
public void afterServing(){
System.out.println("Bye");
}*/
}
在spring配置文件中配置使用@AspectJ切面
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="waiter" class="com.smart.NaiveWaiter"/>
<bean class="com.smart.aspect.aspect.PreGreetingAspect"/>
<!--<bean class="com.smart.aspect.aspect.AfterServingAspect"/>-->
<aop:aspectj-autoproxy/>
</beans>
测试类:
package com.smart.aspect.example;
import com.smart.Waiter;
import com.smart.aspect.aspect.PreGreetingAspect;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath*:spring-config.xml")
public class AspectJProxyTest {
@Autowired(required = true)
private Waiter waiter;
@Test
public void test() {
// ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath*:spring-config.xml");
// Waiter waiter = (Waiter) ctx.getBean("waiter");
waiter.greetTo("mary");
// waiter.serveTo("mary");
}
/*public static void main(String[] args) {
Waiter target = new NaiveWaiter();
AspectJProxyFactory factory = new AspectJProxyFactory();
factory.setTarget(target);
factory.addAspect(PreGreetingAspect.class);
Waiter proxy = factory.getProxy();
proxy.greetTo("john");
proxy.serveTo("john");
}*/
}
运行结果: