注解理解

1. java5之后提供的注解支持

java.lang.annotation提供了四种元注解,专门注解其他的注解:

		@Target 注解用于什么地方默认值为任何元素表示该注解用于什么地方             可用的ElementType指定参数 也同时指定多个        
		   ElementType.CONSTRUCTOR:用于描述构造器    
		   ElementType.FIELD:成员变量对象属性包括enum实例    
		   ElementType.LOCAL_VARIABLE:用于描述局部变量     
		   ElementType.METHOD:用于描述方法     
		   ElementType.PACKAGE:用于描述包     
		   ElementType.PARAMETER:用于描述参数      
		   ElementType.TYPE:用于描述类接口(包括注解类型) 或enum声明        
		  

@Retention –什么时候使用该注解,即注解的生命周期,使用RetentionPolicy来指定

● RetentionPolicy.SOURCE : 在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。@Override, @SuppressWarnings都属于这类注解。

● RetentionPolicy.CLASS : 在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式

● RetentionPolicy.RUNTIME : 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。

@Documented –注解是否将包含在JavaDoc中

@Inherited – 是否允许子类继承该注解

 @Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。    
  如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个   
 annotation将被用于该class的子类。

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})

该注解的作用是,排除自动注入数据源的配置(取消数据库配置),一般使用在客户端(消费者)服务中

当前项目其实并不需要数据源。查其根源是依赖方提供的API依赖中引用了一些多余的依赖触发了该自动化配置的加载。

反射

  1. getFields():获得某个类的所有的公共(public)的字段,包括父类中的字段。
  2. getDeclaredFields():获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的申明字段。
  3. getSuperClass()方法用于返回Class,该Class表示此Class表示的任何类,接口,原始类型或任何void类型的超类。 getSuperclass()方法返回的父类的Class对象。

实际运用

        this.fields = new ArrayList<Object[]>();   
        List<Field> tempFields = new ArrayList<>();      
        //getFields():获得某个类的所有的公共(public)的字段,包括父类中的字段。      
        //getDeclaredFields():获得某个类的所有声明的字段,即包括public、private     和proteced,但是不包括父类的申明字段。     
        //getSuperClass()方法用于返回Class,该Class表示此Class表示的任何类,接口,原始类型或任何void类型的超类。      
        System.out.println(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));        
        System.out.println(Arrays.asList(clazz.getDeclaredFields()));       
        tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));      
        tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));    
          
        解释说明  
            Arrays.asList(clazz.getSuperclass().getDeclaredFields()) 获取的是clazz实例类的父类的所有声明字段类型     
            Arrays.asList(clazz.getDeclaredFields())获取的当前实例clazz的所有声明字段类型不包括父类  
     

反射实际开发使用

1. 访问私有变量

有很多文章讨论禁止通过反射访问一个对象的私有变量,但是到目前为止所有的jdk还是允许通过反射访问私有变量。

使用 Class.getDeclaredField(String name)或者Class.getDeclaredFields()才能获取到私有变量。

	package field;   
	
	import java.lang.reflect.Field;    
	
	public class PrivateField {    
	    protected  String name;    
	
	    public PrivateField(String name){    
	        this.name = name;    
	    }    
	}   
	   
	public class PrivateFieldTest {    
	    public static void main(String args[])throws Exception{    
	        Class privateFieldClass = PrivateField.class;    
	        Field privateName = privateFieldClass.getDeclaredField("name");    
	        privateName.setAccessible(false);    
	        PrivateField privateField = new PrivateField("Alunbar");    
	        String privateFieldValue = (String) privateName.get(privateField);    
	        System.out.println("私有变量值:" + privateFieldValue);    
	    }   
	}    
  

上面的代码有点需要注意:必须调用setAccessible(true)方法,这是针对私有变量而言,public和protected等都不需要。这个方法是允许通过反射访问类的私有变量。

2. 访问私有方法

和私有变量一样,私有方法也是不允许其他的类随意调用的,但是通过反射可以饶过这一限制。 使用Class.getDeclaredMethod(String name, Class[] parameterTypes)或者Class.getDeclaredMethods()方法获取到私有方法。

	public class PrivateMethod {   
	    private String accesPrivateMethod(){    
	        return "成功访问私有方法";    
	    }    
	}   
	
	public class PrivateMethodTest {   
	    public static void main(String args[])throws Exception{   
	        Class privateMethodClass = PrivateMethod.class;   
	
	        Method privateStringMethod = privateMethodClass.getDeclaredMethod    ("accesPrivateMethod", null);   
	        privateStringMethod.setAccessible(true);   
	        String returnValue = (String)privateStringMethod.invoke(new PrivateMethod(), null);   
	
	        System.out.println("returnValue = " + returnValue);   
	    }   
	}   
  

和访问私有变量一样,也要调用setAccessible(true)方法,允许通过反射访问类的私有方法。

3. 访问类注解信息

通过反射可以在运行时获取到类、方法、变量和参数的注解信息。

访问类的所有注解信息:

	Class aClass = TheClass.class;
	Annotation[] annotations = aClass.getAnnotations();
	
	for(Annotation annotation : annotations){
	    if(annotation instanceof MyAnnotation){
	        MyAnnotation myAnnotation = (MyAnnotation) annotation;
	        System.out.println("name: " + myAnnotation.name());
	        System.out.println("value: " + myAnnotation.value());
	    }
	}

访问类特定的注解信息:

	Class aClass = TheClass.class;
	Annotation annotation = aClass.getAnnotation(MyAnnotation.class);
	
	if(annotation instanceof MyAnnotation){
	    MyAnnotation myAnnotation = (MyAnnotation) annotation;
	    System.out.println("name: " + myAnnotation.name());
	    System.out.println("value: " + myAnnotation.value());
	}  

访问方法注解信息:

	Method method = ... //obtain method object
	Annotation[] annotations = method.getDeclaredAnnotations();
	
	for(Annotation annotation : annotations){
	    if(annotation instanceof MyAnnotation){
	        MyAnnotation myAnnotation = (MyAnnotation) annotation;
	        System.out.println("name: " + myAnnotation.name());
	        System.out.println("value: " + myAnnotation.value());
	    }
	}  

访问特定方法注解信息:

	Method method = ... // obtain method object
	Annotation annotation = method.getAnnotation(MyAnnotation.class);
	
	if(annotation instanceof MyAnnotation){
	    MyAnnotation myAnnotation = (MyAnnotation) annotation;
	    System.out.println("name: " + myAnnotation.name());
	    System.out.println("value: " + myAnnotation.value());
	}
  

访问参数注解信息:

	Method method = ... //obtain method object
	Annotation[][] parameterAnnotations = method.getParameterAnnotations();
	Class[] parameterTypes = method.getParameterTypes();
	
	int i=0;
	for(Annotation[] annotations : parameterAnnotations){
	  Class parameterType = parameterTypes[i++];
	
	  for(Annotation annotation : annotations){
	    if(annotation instanceof MyAnnotation){
	        MyAnnotation myAnnotation = (MyAnnotation) annotation;
	        System.out.println("param: " + parameterType.getName());
	        System.out.println("name : " + myAnnotation.name());
	        System.out.println("value: " + myAnnotation.value());
	    }
	  }
	}
  

Method.getParameterAnnotations()方法返回的是一个二维的Annotation数组,其中包含每个方法参数的注解数组。

访问类所有变量注解信息:

	Field field = ... //obtain field object
	Annotation[] annotations = field.getDeclaredAnnotations();
	
	for(Annotation annotation : annotations){
	    if(annotation instanceof MyAnnotation){
	        MyAnnotation myAnnotation = (MyAnnotation) annotation;
	        System.out.println("name: " + myAnnotation.name());
	        System.out.println("value: " + myAnnotation.value());
	    }
	}  

访问类某个特定变量的注解信息:

	Field field = ... // obtain method object
	Annotation annotation = field.getAnnotation(MyAnnotation.class);
	
	if(annotation instanceof MyAnnotation){
	    MyAnnotation myAnnotation = (MyAnnotation) annotation;
	    System.out.println("name: " + myAnnotation.name());
	    System.out.println("value: " + myAnnotation.value());
	}   

再分布式模块中,如何启动类所在的模块没有设计到与数据库的连接时,需要使用exclude去除驱动依赖,如果所在模块设计到与数据库的连接时,则不能添加该字段,否则会报:Property ‘sqlSessionFactory’ or ‘sqlSessionTemplate’ are required错误

@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class },scanBasePackages = { “com.vianet.dcomsp.dwd” })