`

java 注解Annotation

阅读更多

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();// 这个数组的参数在下面
	}
关键字 用途
all to suppress all warnings
boxing  to suppress warnings relative to boxing/unboxing operations
cast to suppress warnings relative to cast operations
dep-ann to suppress warnings relative to deprecated annotation
deprecation to suppress warnings relative to deprecation
fallthrough  to suppress warnings relative to missing breaks in switch statements
finally  to suppress warnings relative to finally block that don’t return
hiding to suppress warnings relative to locals that hide variable
incomplete-switch  to suppress warnings relative to missing entries in a switch statement (enum case)
nls  to suppress warnings relative to non-nls string literals
null to suppress warnings relative to null analysis
rawtypes to suppress warnings relative to un-specific types when using generics on class params
restriction to suppress warnings relative to usage of discouraged or forbidden references
serial to suppress warnings relative to missing serialVersionUID field for a serializable class
static-access o suppress warnings relative to incorrect static access
synthetic-access   to suppress warnings relative to unoptimized access from inner classes
unchecked  to suppress warnings relative to unchecked operations
unqualified-field-access to suppress warnings relative to field access unqualified
unused to suppress warnings relative to unused code

 

 下面举一个栗子 

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

 

 

 

spring注解

 

赋值注解和初始化注解是分开的
@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 注入之前将这两种配置方式的元信息融合在一起。
1
4
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics