注解和反射

本文介绍了Java中的注解和反射。注解的作用包括编译指导、编译时生成代码和运行时处理,如@Deprecated、@Override。元注解如@Target、@Retention和@Inherited用于修饰注解。反射则允许程序在运行时获取类的所有信息,包括Class对象的获取和使用,以及通过反射进行对象创建和方法调用。文章还进行了反射性能测试,并简述了反射框架Reflects。最后,讨论了一个简易IOC容器的实现,利用注解扫描和反射创建Bean。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、注解

1.1、注解的作用

1)编译指导,比如java内置的三个注解,(@Override,@Deprecated,@SuppressWarnings)可以对编译器辅助使用。

@Override对父类或者接口的某个方法进行重写的时候使用,如果方法名出错,会有相应的编译异常提示;如果没有加这个注解,那么就算是写错了名称,也不会有异常提示。

@Deprecated 过期提示,当被改注解标注的方法,类等被使用时,会在有删除线提示,表示不推荐使用,后续版本会进行移除,一般点入api,都会有相关替代的方法可以找到。

 

@SuppressWarnings镇压警告,比如过期出现删除线的方法,一类类型检查(出现黄色的),比如:

 

 

将@SuppressWarnings("all")加入到上述的类中:警告就会消失

 

不过一般不这样做,过期的api,点进去总会有替代的api使用,比如版本为:1.16.12的lombok的@Builder注解,lombok.experimental.Builder这个包下的注解提示是过期的,如下:

 

在idea中,这个会有警告提示,但是不影响代码运行,不过看着也很别扭,可以加一个

@SuppressWarnings("all")注解,不过不推荐这样使用,一般点进去,都会有相应的替代方法:里面发现注释:

@deprecated {@link lombok.Builder} has been promoted to the main package, so use that one instead.

就是说使用:lombok.Builder 替代lombok.experimental.Builder,引入lombok.Builder这个注解即可。lombok.experimental.Builder这个注解在1.18.12的版本中已经被移除了的。

 

2)编译时生成代码,比如一些构建工具生成代码,xml文件等

 

3)运行时通过反射进行处理,可以用于生成对象,初始化,生成代码等

 

1.2、元注解

元注解就是修饰注解的注解:

@Target 注解作用的位置,可以在class, method, field等上面使用

ElementType:
   TYPE: 可以在类,接口上使用
   FIELD: 属性上使用
   METHOD: 方法上使用
   PARAMETER: 方法参数上使用
   ...

@Retention 作用的范围: source (源码)< class(编译后产生的class文件) < runtime(代码运行的时候)

@Document 将注解的信息生成放到Javadoc中

package cn.yishijie.test;
​
import java.lang.annotation.*;
​
@Documented
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyDocument {
​
    String value() default "javaDoc annotation";
​
    String author() default "jeff.chan";
}
​
package cn.yishijie.test;
​
@MyDocument(value = "this is a person class", author = "jeff.chan")
public class Person {
​
    private int age;
    private String name;
​
    public int getAge() {
        return age;
    }
​
    public void setAge(int age) {
        this.age = age;
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
}

如下图:

 

如果注解没有被@Document修饰,那么将不会出现在javadoc中

 

@Inherited 子类可以继承父类的注解

如果一个类的父类(接口不行)被某个注解修饰,而这个注解里有@Inherited修饰,那么子类将会继承父类的注解。

@Inherited
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyInherit {
}
​
@MyInherit
public class Father {
}
​
public class Son extends Father{
}
​
public class Client {
​
    public static void main(String[] args) {
        Class<?> sonClass = Son.class;
​
        MyInherit annotation = sonClass.getAnnotation(MyInherit.class);
        System.out.println(annotation);
    }
}

上述的客户端,会打印出@MyInherit注解,说明子类Son继承了父类的注解

 

2、反射

 反射可以动态获取一个类的所有信息

 Class类用于表示字节码文件.class,在使用反射之前,需要得到Class对象,只要类型和维度一样,就是同一个Class对象,jvm在加载类到内存时,会生成Class对象,用于表示该类信息,并且只有一份。

 2.1、获取Class对象的三种方式:

//第一种方式
Class<?> aClass = Person.class;

//第二种方式
Class<? extends Person> aClass1 = new Person().getClass();

//第三种方式,如果对应的全类名不存在,那么会抛出ClassNotFoundException
Class<?> aClass2 = Class.forName("reflect.Person");

 2.2、Class对象的使用:

// 获取类名
String simpleName = aClass.getSimpleName();
// 获取全类名
String name = aClass.getName();
// 获取所有注解
Annotation[] annotations = aClass.getAnnotations();
// 获取指定的注解
MyAnnotation annotation = aClass.getAnnotation(MyAnnotation.class);

// 获取所有的属性
Field[] declaredFields = aClass.getDeclaredFields();
// 获取public类型的属性
Field[] fields = aClass.getFields();
// 获取public指定的属性名
// Field field = aClass.getField("name");
// 获取定义的属性名
Field field1 = aClass.getDeclaredField("name");

// 创建对象
Object obj = aClass.newInstance();
// 使用私有属性的时候要做以下操作
// 否则会报错
field1.setAccessible(true);
// 设置实列的属性值
field1.set(obj,"jeffchan");

// 获取所有的public方法
Method[] methods = aClass.getMethods();
// 获取public指定的方法名
Method setName = aClass.getMethod("setName", String.class);
// 获取所有声明的方法
Method[] declaredMethods = aClass.getDeclaredMethods();
// 获取指定的声明的方法
Method setName1 = aClass.getDeclaredMethod("setName", String.class);
// 如果是调用私有的方法,要关闭java访问权限的检查
setName.setAccessible(true);
// 调用方法
setName.invoke(obj, "caraliu");

// 获取所有public的构造器
Constructor<?>[] constructors = aClass.getConstructors();

// 获取所有声明的构造器
Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();

// 获取public指定的构造器
Constructor<?> constructor = aClass.getConstructor(String.class, String.class);
// 创建实列
Object obj1 = constructor.newInstance("jeffchan", "23");

上述的方法,属性,构造器获取都是有public,声明,具体指定的public,具体指定的声明这四种方式

 

2.3、反射性能测试

package cn.yishijie;

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

@BenchmarkMode(Mode.AverageTime) // 测试方法平均执行时间
@OutputTimeUnit(TimeUnit.MICROSECONDS) // 输出结果的时间粒度为微秒
@State(Scope.Thread) // 每个测试线程一个实例
public class FirstBenchMark {
    @Benchmark
    public void normal() {
        Person p =new Person();
        for (int i = 0; i< 1000000; i++) {
            p.setName(""+i);
        }
    }

    @Benchmark
    public void reflectWithAccessible() throws Exception {
        Class<?> aClass = Class.forName("cn.yishijie.Person");
        Object obj = aClass.newInstance();
        Method name = aClass.getMethod("setName", String.class);
        // 去掉访问控制校验
        name.setAccessible(true);
        for (int i = 0; i< 1000000; i++) {
            name.invoke(obj,""+i);
        }
    }

    @Benchmark
    public void reflect() throws Exception {
        Class<?> aClass = Class.forName("cn.yishijie.Person");
        Object obj = aClass.newInstance();
        Method name = aClass.getMethod("setName",String.class);
        for (int i = 0; i< 1000000; i++) {
            name.invoke(obj,""+i);
        }
    }
    
    public static void main(String[] args) throws RunnerException {

        Options opt = new OptionsBuilder()
                .include(FirstBenchMark.class.getSimpleName())
                .forks(1) // 一个线程程执行测试
                .warmupIterations(5) // 执行5遍warmup
                .measurementIterations(5) // 执行5遍测试
                .build();
        new Runner(opt).run();
    }
}

结果输出:

Result "cn.yishijie.FirstBenchMark.normal":
  15743.863 ±(99.9%) 96.377 us/op [Average]
  (min, avg, max) = (15724.352, 15743.863, 15785.170), stdev = 25.029
  CI (99.9%): [15647.486, 15840.240] (assumes normal distribution)

 

Result "cn.yishijie.FirstBenchMark.reflect":
  16343.323 ±(99.9%) 126.123 us/op [Average]
  (min, avg, max) = (16321.565, 16343.323, 16400.679), stdev = 32.754
  CI (99.9%): [16217.201, 16469.446] (assumes normal distribution)

 

Result "cn.yishijie.FirstBenchMark.reflectWithAccessible":
  15812.856 ±(99.9%) 183.979 us/op [Average]
  (min, avg, max) = (15787.033, 15812.856, 15898.016), stdev = 47.779
  CI (99.9%): [15628.878, 15996.835] (assumes normal distribution)

 

普通的平均耗时:  15743.863 微秒

加访问控制的反射耗时:  16343.323 微秒

不加访问控制的反射耗时:15812.856 微秒

普通的平均耗时 < 不加访问控制校验的反射耗时 < 加访问控制校验的反射耗时

说明反射会一定的性能损耗,尤其是实际工作中比较复杂的场景,这种损耗会更加明显,同时访问权限的校验过程也会耗一定时间。

 

2.4、反射框架Reflects介绍

创建Reflections实列的三种方式:

Reflections reflections = new Reflections("my.package.prefix");
//or
Reflections reflections = new Reflections(ClasspathHelper.forPackage("my.package.prefix"), 
            new SubTypesScanner(), new TypesAnnotationScanner(), new FilterBuilder().include(...), ...);
​
//or using the ConfigurationBuilder
new Reflections(new ConfigurationBuilder()
            .filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix("my.project.prefix")))
            .setUrls(ClasspathHelper.forPackage("my.project.prefix"))
            .setScanners(new SubTypesScanner(), new TypeAnnotationsScanner().filterResultsBy(optionalFilter), ...));
// 扫描当前包和子包下的文件的实列对象
Reflections reflections = new Reflections(Client.class.getPackage().getName()
        , new SubTypesScanner() // 子类型扫描器
        , new FieldAnnotationsScanner() // 属性注解扫描器
        , new TypeAnnotationsScanner()); // 注解类型扫描器

// 在当前包和子包下获取所有MyInterface的实现类
Set<Class<? extends MyInterface>> subTypes = reflections.getSubTypesOf(MyInterface.class);
//subTypes.forEach(x -> System.out.println(x));

// 在当前包和子包下获取所有被@MyDocument修饰的类
Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(MyDocument.class);
//annotated.forEach(x -> System.out.println(x));

// honorInherited这个参数是作用于@Inherited这个注解,如果为true的话,那么跟@Inherited的作用一样
// 如果为false,那么注解都会被子类继承,不管是不是接口,默认为false
Set<Class<?>> typesAnnotatedWith = reflections.getTypesAnnotatedWith(MyInherit.class,false);
typesAnnotatedWith.forEach(x -> System.out.println(x));

// 获取被@Id注解修饰的属性
Set<Field> fieldsAnnotatedWith = reflections.getFieldsAnnotatedWith(Id.class);
fieldsAnnotatedWith.forEach(x -> System.out.println(x));

还有很多API,参考文献地址: http://ronmamo.github.io/reflections/index.html?org/reflections/Reflections.html

 

3、简易IOC容器

自定义注解:(Autowired Compenent Repository Service)

package cn.yishijie.annotation;

import java.lang.annotation.*;

@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
}

package cn.yishijie.annotation;

import java.lang.annotation.*;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Component {

    String value() default "";
}


package cn.yishijie.annotation;

import java.lang.annotation.*;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Repository {

    String value() default "";
}


package cn.yishijie.annotation;

import java.lang.annotation.*;

@Documented
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Service {

   String value() default "";
}

后置处理器接口定义:

package cn.yishijie.processor;

public interface BeanPostProcessor {

    Object postProcessAfterInitialization(Object bean, String beanName);
}

反射封装的工具类:

package cn.yishijie.util;

import lombok.extern.slf4j.Slf4j;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.scanners.TypeAnnotationsScanner;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Set;

@Slf4j
public class ReflectionsUtil {

    /**
     * 获取某个包下的注解
     * @param packageName
     * @param annotation
     * @return
     */
    public static Set<Class<?>> scanAnnotatedClass(String packageName, Class<? extends Annotation> annotation){
        Reflections reflections = new Reflections(packageName,new SubTypesScanner(), new TypeAnnotationsScanner());
        Set<Class<?>> annotatedClass = reflections.getTypesAnnotatedWith(annotation);
        return annotatedClass;
    }

    /**
     * 实列化
     * @param cls
     * @return
     */
    public static Object newInstance(Class<?> cls) {
        Object instance = null;
        try {
            instance = cls.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            log.error("new instance failed", e);
        }
        return instance;
    }

    /**
     * 设置属性
     * @param obj
     * @param field
     * @param value
     */
    public static void setField(Object obj, Field field, Object value) {
        // 忽略java访问权限的校验
        field.setAccessible(true);
        try {
            field.set(obj, value);
        } catch (IllegalAccessException e) {
            log.error("set field failed", e);
            e.printStackTrace();
        }
    }

    /**
     * 获取某个包下的某个类的所有子类
     * @param packageName
     * @param interfaceClass
     * @param <T>
     * @return
     */
    public static <T> Set<Class<? extends T>> getSubClass(String packageName, Class<T> interfaceClass) {
        Reflections reflections = new Reflections(packageName,new SubTypesScanner());
        return reflections.getSubTypesOf(interfaceClass);
    }
}

注解扫描和后置处理器列表:

package cn.yishijie.core.ioc;

import cn.yishijie.IocApplication;
import cn.yishijie.annotation.Component;
import cn.yishijie.annotation.Repository;
import cn.yishijie.annotation.Service;
import cn.yishijie.processor.BeanPostProcessor;
import cn.yishijie.util.ReflectionsUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class AnnotationScanner {

     public static final Map<String, Class<?>> annotationClassMap = new ConcurrentHashMap<>();
     // 后置处理器列表
     public static final List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();

     public static void scanAnnotationClasses(String packageName){
         Set<Class<?>> componentClass = ReflectionsUtil.scanAnnotatedClass(packageName, Component.class);
         Set<Class<?>> serviceClass = ReflectionsUtil.scanAnnotatedClass(packageName, Service.class);
         Set<Class<?>> repositoryClass = ReflectionsUtil.scanAnnotatedClass(packageName, Repository.class);
         componentClass.forEach(x -> {
             annotationClassMap.put(BeanFactory.getBeanName(x), x);
         });
         serviceClass.forEach(x -> {
             annotationClassMap.put(BeanFactory.getBeanName(x), x);
         });
         repositoryClass.forEach(x -> {
             annotationClassMap.put(BeanFactory.getBeanName(x), x);
         });

         Set<Class<? extends BeanPostProcessor>> subClass = ReflectionsUtil.getSubClass(IocApplication.class.getPackage().getName(), BeanPostProcessor.class);
         subClass.forEach(x -> beanPostProcessors.add((BeanPostProcessor) ReflectionsUtil.newInstance(x)));
     }
}

Bean工厂:

package cn.yishijie.core.ioc;

import cn.yishijie.IocApplication;
import cn.yishijie.annotation.Autowired;
import cn.yishijie.annotation.Component;
import cn.yishijie.annotation.Repository;
import cn.yishijie.annotation.Service;
import cn.yishijie.processor.BeanPostProcessor;
import cn.yishijie.util.ReflectionsUtil;

import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class BeanFactory {
    private static BeanFactory beanFactory = new BeanFactory();
    public final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(128);
    public final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(128);


    private BeanFactory(){
    }

    public static BeanFactory beanFactory(){
        return beanFactory;
    }

    /**
     * 获取容器中的beanName
     * @param aClass
     * @return
     */
    public  static String getBeanName(Class<?> aClass) {
        String beanName = aClass.getName();
        if (aClass.isAnnotationPresent(Component.class)) {
            Component component = aClass.getAnnotation(Component.class);
            beanName = "".equals(component.value()) ? aClass.getName() : component.value();
        }
        if(aClass.isAnnotationPresent(Service.class)){
            Service service = aClass.getAnnotation(Service.class);
            beanName = "".equals(service.value()) ? aClass.getName() : service.value();
        }
        if(aClass.isAnnotationPresent(Repository.class)){
            Repository repository = aClass.getAnnotation(Repository.class);
            beanName = "".equals(repository.value()) ? aClass.getName() : repository.value();
        }
        return beanName;
    }

    public Object getBean(String beanName) throws Exception{
        Object obj = singletonObjects.get(beanName);
        if(obj == null){
            Class<?> aClass = AnnotationScanner.annotationClassMap.get(beanName);
            if(aClass == null){
                return obj;
            }
            if(!earlySingletonObjects.keySet().contains(beanName)){
                obj = aClass.newInstance();
                // 用于解决循环依赖问题,提前暴露初步实列化的对象
                earlySingletonObjects.put(beanName, obj);
            }
            Field[] fields = aClass.getDeclaredFields();
            if(fields.length > 0){
                for(Field field : fields){
                    if(field.isAnnotationPresent(Autowired.class)){
                        Class<?> fieldClass = field.getType();
                        if (fieldClass.isInterface()){
                            Set<Class<?>> subClasses = ReflectionsUtil.getSubClass(IocApplication.class.getPackage().getName(), (Class<Object>)fieldClass);
                            if (subClasses.size() == 0) {
                                throw new Exception(field.getName() + " is interface and do not have implemented class exception");
                            }
                            if (subClasses.size() == 1) {
                                fieldClass = subClasses.iterator().next();
                            }
                            if (subClasses.size() > 1) {
                                throw new Exception(field.getName() + " is interface more than one implement");
                            }
                        }
                        String fieldBeanName = getBeanName(fieldClass);
                        Object existObj = singletonObjects.get(fieldBeanName);
                        if(existObj != null){
                            // 设置注入属性
                            ReflectionsUtil.setField(obj,field,existObj);
                        }else{
                            Object earlyObjects = earlySingletonObjects.get(fieldBeanName);
                            if(earlyObjects != null){
                                // 设置注入属性
                                ReflectionsUtil.setField(obj,field,earlyObjects);
                            }else {
                                // 设置注入属性                                
                              ReflectionsUtil.setField(obj,field,getBean(fieldBeanName));
                            }
                        }
                    }
                }
                earlySingletonObjects.remove(beanName);
            }
            if(!singletonObjects.keySet().contains(beanName)){
                singletonObjects.put(beanName, obj);
                // 实列化完成后,调用后置处理器的方法
                postProcess(obj, beanName);
            }
        }
        return obj;
    }

    /**
     * 执行后置处理器
     * @param bean
     * @param beanName
     * @return
     */
    public Object postProcess(Object bean, String beanName){
        for (BeanPostProcessor beanPostProcessor : AnnotationScanner.beanPostProcessors) {
            bean = beanPostProcessor.postProcessAfterInitialization(bean, beanName);
        }
        return bean;
    }
}

ApplicationContext:

package cn.yishijie.core.ioc;

public class ApplicationContext {


    public void refresh(String packageName) {
        AnnotationScanner.scanAnnotationClasses(packageName);
    }

    public Object getBean(String beanName) throws Exception{
        BeanFactory beanFactory =  BeanFactory.beanFactory();
        return beanFactory.getBean(beanName);
    }
}

客户端调用:

package cn.yishijie;

import cn.yishijie.core.ioc.ApplicationContext;


public class IocApplication {

    public static void main(String[] args) throws Exception{
        ApplicationContext applicationContext = new ApplicationContext();
        applicationContext.refresh(IocApplication.class.getPackage().getName());
        Object useDao = applicationContext.getBean("userDao");
        System.out.println(useDao);
    }
}

上述功能中,没有实现@Qualified等注解的功能,也没有提供Bean的init()方法,并且都是懒加载的方式,要实际使用到某个对象的时候,才会创建实例,并且放入到Map中,下次拿的时候,是同一个bean。这里简单的使用到了注解的扫描解析和反射功能。实际可以通过这些来完成更复杂的功能,比如增加netty充当服务器,mvc的url映射功能可以制作一个简单的springboot项目。

 

作者 : jeff.chan

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值