应用动态代理技术要先掌握annotation技术
注解是JDK1.5之后才有的新特性,JDK1.5之后内部提供的三个注解
@Deprecated 意思是“废弃的,过时的”
@Override 意思是“重写、覆盖”
@SuppressWarnings 意思是“压缩警告”
注解可以加在类名,方法,参数,属性等,为开发者自定义编译处理,JPA是基于注解的,Spring2.5以上都是基于注解的,Hibernate3.x以后也是基于注解
所以注解是做框架必备技术
先来看看如何书写Annotation
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.CLASS) public @interface TestAnno{ int value(); String name() default ""; }
1.书写跟interface一样,前面加了个@符号
2.属性可以加默认值
3.@Target 是使用权,作用于类名,方法,参数,属性等地方,可以有多个使用权
4.@Retention 是决定注解生命周期 ,分别为 SOURCE,CLASS,RUNTIME 第一个权限越低
SOURCE 只是在源码上保留,java文件编译成class去掉
CLASS 保留在class但在加载时忽略
RUNTIME 保留在class并加载时保留
来验证下@Retention
import java.lang.reflect.Field; public class TestAnnotation { @TestAnno(value = 1, name = "a") private int a; public static void main(String[] args) { for (Field field : TestAnnotation.class.getDeclaredFields()) { TestAnno anno = field.getAnnotation(TestAnno.class); System.out.println(anno.value()); } } }
执行结果:
Exception in thread "main" java.lang.NullPointerException
at com.eyu.onequeue.TestAnno.main(TestAnno.java:13)
我们来修改下@Retention(RetentionPolicy.RUNTIME)
再执行就正常了
接下来看看spring是如何应用注解技术的
如spring切面拦截
@Aspect public class TestAspect {
@Around("@annotation(annotation class)") public Object exceptionHandler(ProceedingJoinPoint pjp) throws Throwable { Object result = pjp.proceed(pjp.getArgs()); return result; } }
1.@Aspect将处理范围准确到类,一个处理对应一个注解
2.扫描每个类的属性或方法,提取@Around的信息
3.提取后应缓存起来,不用每次重新处理
我们来看下为什么要缓存起来
在main里加一行System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
运行后 用jd-gui打开 $Proxy1,只是分析value方法,可以看到用反射invoke执行结果,而invoke执行比较耗时
public final int value() { try { return ((Integer)this.h.invoke(this, m4, null)).intValue(); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } }
接下来看看Hibernate应用
@Entity @NamedQueries({ @NamedQuery(name = Player.ACCOUNT2ID, query = "select account, id from Player"), @NamedQuery(name = Player.ONLINE_IDS, query = "select id from Player WHERE logined = 1"), }) public class Player { static final String ACCOUNT2ID = "Player_Account2Id"; public static final String ONLINE_IDS = "Player_ONLINE_IDS"; static final String IDX_ACCOUNT = "Player_Account"; @Id private long id; @Index(name = IDX_ACCOUNT) @Column(unique = true, nullable = false) private String account; private Date createdOn;
//.....省略 }
1.@Entity是处理的标记 @Id作为table主健
2.@Column 映射列属性,如自定义列名,是否唯一,不能为NULL等
3.@Index 生成索引
4.@NamedQuery 绑定hql语句
小结:只要在原对象结构基础上加上注解,无破坏性,优雅的方式就能实现复杂的功能,还有个好处就是硬编译写在class上的,不用每次调用再去执行其它IO处理,一切尽在掌握之中