1.创建一个注解
创建注解跟接口差不多,不过要在interface前加个@,可以用default在方法后面设置默认值,方法的返回类型包括基本类型、String、Class、enum、Annotation、以上类型数组。还要通过元注解(@Retention、@Target)定义其作用域、有效范围。举一个栗子
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.ANNOTATION_TYPE}) public @interface demo{ public int value();//只有当value()是唯一需要使用时赋值,才可以这样简写@demo(0) public String bbb() default "demo"; public Class<?> ccc() default Date.class; public ElementType ddd() default ElementType.TYPE; public Target eee() default @Target(value = { ElementType.TYPE }); public char[] fff() default {'a','b'}; }
2.元注解
元注解专职负责注解其他注解,共四种 @Target、@Retention保留、@Documented(将此注解包含在Javadoc中)、@Inherited(允许子类继承父类),其实元注解跟泛型的通配符(?)差不多概念。先介绍下注解中用到的两个枚举参数
元注解@Target的参数
public enum ElementType {// 分别表示的作用范围 TYPE, // 类、接口、注解、泛型 FIELD, // 域 METHOD, // 方法 PARAMETER, // 参数 CONSTRUCTOR, // 构造方法 LOCAL_VARIABLE, // 局部变量 ANNOTATION_TYPE, // 应用于另一个注解上 PACKAGE; // 包 private ElementType() {} }
元注解@Retention的参数
public enum RetentionPolicy { SOURCE, //注解将被编译器丢弃 CLASS, //保存在class文件中,VM 丢弃 RUNTIME; //运行时保留,可通过反射获取 private RetentionPolicy() {} }
元注解@Target,表示该注解可以用在什么地方
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.ANNOTATION_TYPE}) public @interface Target { ElementType[] value(); }
元注解@Retention,注解的保存级别
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.ANNOTATION_TYPE}) public @interface Retention { RetentionPolicy value(); }
3. Java内置注解
@Override, 表示当前方法覆盖父类中的方法,如果父类没有该方法,编译器错误
//源码 @Target({ElementType.METHOD}) @Retention(RetentionPolicy.SOURCE) public @interface Override {}
@Deprecated, 用这个标注方法,就会出现一条横线,方法就基本废了
//源码 @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD, ElementType.PACKAGE, ElementType.PARAMETER, ElementType.TYPE}) public @interface Deprecated {}
@SuppressWarnings({"all"}) 消除警告用
//源码 @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.CONSTRUCTOR, ElementType.LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { String[] value();// 这个数组的参数在下面 }
|
下面举一个栗子
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Collections; import java.util.LinkedList; import java.util.Queue; public class AnnotationTest implements InvocationHandler { private Object obj; public AnnotationTest(Object obj) { this.obj = obj; } // ----------------定义注解-------------------- // 让此枚举保留到运行时 @Retention(RetentionPolicy.RUNTIME) // 用在方法上 @Target({ ElementType.METHOD }) public @interface Transaction { public boolean value() default true; } // ---------------定义一个接口------------------ public interface IDao { @Transaction // 使用注解 public void remove(); } // --------------实现接口--------------------- public static class DaoImpl implements IDao { Queue<String> queue; public DaoImpl(Queue<String> queue) { this.queue = queue; } @Override public void remove() { // 删除报错,要求回滚 if (queue.peek().equals("stop")) { throw new NullPointerException(); } System.err.println(queue.poll()); } } // --------------得到代理类--------------------- public Object getProxy() { return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(), this); } @Override public Object invoke(Object paramObject, Method paramMethod, Object[] paramArrayOfObject) throws Exception { // 取方法上面的注解Transaction Transaction tran = paramMethod.getAnnotation(Transaction.class); boolean isTran = false; if (tran != null) { isTran = tran.value();// 判断是否需要事务 } Object rtnObj = null; try { if(isTran){System.err.println("启动事务");} rtnObj = paramMethod.invoke(obj, paramArrayOfObject); if(isTran){System.err.println("提交事务");} }catch(Exception e){ if(isTran){System.err.println("回滚事务");} throw e; } return rtnObj; } public static void main(String[] args) { Queue<String> queue = new LinkedList<String>(); Collections.addAll(queue, "1", "stop", "2"); AnnotationTest test = new AnnotationTest(new DaoImpl(queue)); IDao dao = (IDao) test.getProxy(); try { while (queue.peek() != null) { dao.remove(); } } catch (Exception e) { System.out.println("-----------------"); for (String str : queue) { System.out.println(str); } } } }
输出:
启动事务
1
提交事务
启动事务
回滚事务
-----------------
stop
2
赋值注解和初始化注解是分开的
@Autowired (赋值注解,默认按照类型匹配)
<!-- 该 BeanPostProcessor 将自动起作用,对标注 @Autowired 的 Bean 进行自动注入 --> <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
当不能确定 Spring 容器中一定拥有某个类的 Bean 时,可以在需要自动注入该类 Bean 的地方可以使用 @Autowired(required = false),这等于告诉 Spring:在找不到匹配 Bean 时也不报错。
当遇到一个对象不止有一个实例时,按照bean的id进行注解
@Autowired public void setOffice(@Qualifier("office")Office office) { this.office = office; }
在xml中配置的bean 都可以通过该注解
可以对私有成员变量进行注解(不需要set方法也可以)
注解在set方法上
注解在构造方法
@Resource 的作用相当于 @Autowired,只不过 @Autowired 按 byType 自动注入,面@Resource 默认按 byName 自动注入罢了@Resource 有两个属性是比较重要的,分别是 name 和 type,Spring 将@Resource 注释的 name 属性解析为 Bean 的名字,而 type 属性则解析为 Bean 的类型。所以如果使用 name 属性,则使用 byName 的自动注入策略,而使用 type 属性时则使用 byType 自动注入策略。如果既不指定 name 也不指定 type 属性,这时将通过反射机制使用 byName 自动注入策略
让JSR-250的注释生效
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>
JSR-250 为初始化之后/销毁之前方法的指定定义了两个注释类,分别是 @PostConstruct 和 @PreDestroy,这两个注释只能应用于方法上。标注了 @PostConstruct 注释的方法将在类实例化后调用,而标注了 @PreDestroy 的方法将在类销毁之前调用。
清单 17. 使用 @PostConstruct 和 @PreDestroy 注释的 Boss.java
package com.baobaotao; import javax.annotation.Resource; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; public class Boss { @Resource private Car car; @Resource(name = "office") private Office office; @PostConstruct public void postConstruct1(){ System.out.println("postConstruct1"); } @PreDestroy public void preDestroy1(){ System.out.println("preDestroy1"); } … }
您只需要在方法前标注 @PostConstruct 或 @PreDestroy,这些方法就会在 Bean 初始化后或销毁之前被 Spring 容器执行了。
我们知道,不管是通过实现 InitializingBean/DisposableBean 接口,还是通过 <bean> 元素的init-method/destroy-method 属性进行配置,都只能为 Bean 指定一个初始化 / 销毁的方法。但是使用 @PostConstruct 和 @PreDestroy 注释却可以指定多个初始化 / 销毁方法,那些被标注 @PostConstruct 或 @PreDestroy 注释的方法都会在初始化 / 销毁时被执行。
注解用于初始化
<context:component-scan base-package="com.baobaotao"/>
Spring 2.5 在 @Repository 的基础上增加了功能类似的额外三个注解:
@Component 是一个泛化的概念,仅仅表示一个组件 (Bean) ,可以作用在任何层次。
@Service 通常作用在业务层,但是目前该功能与 @Component 相同。
@Constroller 通常作用在控制层,但是目前该功能与 @Component 相同。
@Component 有一个可选的入参,用于指定 Bean 的名称,在 Boss 中,我们就将 Bean 名称定义为“boss”。一般情况下,Bean 都是 singleton 的,需要注入 Bean 的地方仅需要通过 byType 策略就可以自动注入了,所以大可不必指定 Bean 的名称。
@Component 定义的 Bean 都是 singleton 的
----------------每次是一个新实例------------
@Scope("prototype") @Component("boss") public class Boss { … }
Spring 2.5 中除了提供 @Component 注释外,还定义了几个拥有特殊语义的注释,它们分别是:@Repository、@Service 和@Controller。在目前的 Spring 版本中,这 3 个注释和 @Component 是等效的,但是从注释类的命名上,很容易看出这 3 个注释分别和持久层、业务层和控制层(Web 层)相对应。虽然目前这 3 个注释和@Component 相比没有什么新意,但 Spring 将在以后的版本中为它们添加特殊的功能。所以,如果 Web 应用程序采用了经典的三层分层结构的话,最好在持久层、业务层和控制层分别采用@Repository、@Service 和 @Controller 对分层中的类进行注释,而用@Component 对那些比较中立的类进行注释。
- 注释配置不一定在先天上优于 XML 配置。如果 Bean 的依赖关系是固定的,(如 Service 使用了哪几个 DAO 类),这种配置信息不会在部署时发生调整,那么注释配置优于 XML 配置;反之如果这种依赖关系会在部署时发生调整,XML 配置显然又优于注释配置,因为注释是对 Java 源代码的调整,您需要重新改写源代码并重新编译才可以实施调整。
- 如果 Bean 不是自己编写的类(如 JdbcTemplate、SessionFactoryBean 等),注释配置将无法实施,此时 XML 配置是唯一可用的方式。
-
注释配置往往是类级别的,而 XML 配置则可以表现得更加灵活。比如相比于 @Transaction 事务注释,使用 aop/tx 命名空间的事务配置更加灵活和简单。
所以在实现应用中,我们往往需要同时使用注释配置和 XML 配置,对于类级别且不会发生变动的配置可以优先考虑注释配置;而对于那些第三方类以及容易发生调整的配置则应优先考虑使用 XML 配置。Spring 会在具体实施 Bean 创建和 Bean 注入之前将这两种配置方式的元信息融合在一起。
相关推荐
Java注解Annotation用起来很方便,也越来越流行,由于其简单、简练且易于使用等特点,很多开发工具都提供了注解功能,不好的地方就是代码入侵比较严重,所以使用的时候要有一定的选择性。 这篇文章将利用注解,来做...
Java注解(Annotation)自JDK 5.0引入以来,已经成为Java语言的重要特性之一,它为代码元数据提供了一种标准化的方式,使得编译器、工具和其他框架能够理解和处理这些元数据。在Java中,注解是一种元数据,可以被...
Java注解(Annotation)是Java语言提供的一种元数据机制,用于向编译器或JVM提供额外的信息。这些信息可以用来验证代码、控制代码生成、配置应用等。注解是自Java 5版本引入的特性,它使得程序员可以在源代码中嵌入...
Java注解,也称为 Annotation,是Java编程语言中的一种元数据机制,用于向编译器、JVM(Java虚拟机)或工具提供有关代码的信息。这些信息可以用来进行编译时检查、运行时处理,或者作为配置信息。注解不是程序的一...
Java 5引入的注解(Annotation)是一种元数据,它提供了在代码中嵌入信息的方式,这些信息可以被编译器、JVM或其他工具在编译时或运行时使用。注解可以用来简化代码,提高可维护性,并帮助工具进行静态分析。 1. ...
Java 1.5 引入了一种新的元编程机制——注解(Annotation),极大地增强了代码的可读性和可维护性。注解是一种在代码中添加元数据的方式,它允许程序员在源代码上添加一些信息,这些信息可以被编译器或运行时环境...
### Java自定义注解Annotation的使用 #### 1. 前言 自从JDK 1.5引入了注解这一特性以来,它已经成为Java开发中的一个重要组成部分。注解最初是为了推动EJB 3.0的普及和发展而设计的,其目的是减少配置文件的使用,...
Java 注解(Annotation) - 请认准 ih0qtq
Java注解(Annotation)是Java语言的一个重要特性,它为元数据提供了强大的支持。元数据是一种描述数据的数据,可以提供有关代码的附加信息,而这些信息并不直接影响代码的执行。在Java中,注解用于向编译器、JVM或...
Java.Annotation注解.part4
Java Annotation注解技术是自Java SE 5.0版本引入的一种元编程机制,它允许程序员在源代码的各个层面(如类、方法、变量等)添加元数据,以供编译器、JVM或第三方工具在编译时或运行时进行处理。Annotation简化了...
Java注解,也称为Annotation,是Java编程语言中的一种特性,用于向编译器、JVM或工具提供元数据。元数据是关于数据的数据,它提供了额外的信息,但不直接影响程序的执行。注解在代码中以`@注解名`的形式出现,主要...
如果你想知道java annotation是什么?你可以看看
Java注解(Annotation)是Java语言中的一个重要特性,自Java 1.5版本引入以来,它在软件开发中扮演了不可或缺的角色。注解是一种元数据,它可以附加到源代码的不同元素上,如类、方法、变量等,提供了额外的信息,...
Java.Annotation注解.part3
Java.Annotation注解.part2
Java.Annotation注解.part1
Java注解(Annotation)是Java语言中的一个重要特性,它允许程序员在源代码中嵌入元数据(metadata),这些元数据不会直接影响程序的执行,但可以被编译器或Java虚拟机(JVM)在编译时或运行时读取,从而实现特定的...
在实际开发中,Java注解被广泛用于Spring框架的依赖注入、JPA的实体映射、JSF的UI组件绑定等场景,极大地提高了代码的可维护性和灵活性。然而,对于更复杂的注解使用,如自定义注解生成XML映射文件,需要更深入的...