spring框架创建bean就是利用反射机制

发布时间:2026/7/1 9:27:23
spring框架创建bean就是利用反射机制 public static void main(String[] args) throws Exception { System.out.println(Hello, World!); // 使用反射机制调用方法 // 获取类 Class? clazz Class.forName(com.ali.bean2.SomeService); // 获取方法 Method method clazz.getMethod(doSomething, String.class, int.class); // 获取对象 Object obj clazz.newInstance(); // 方法调用 // obj: 哪个对象调用这个方法 // hello, 42: 方法参数 // hello: 方法的返回值 Object hello method.invoke(obj, hello, 42); }spring IoC注解式开发注解主要是为了简化xml配置。注解怎么定义新建Java Class 时选择Annoation 类型的文件这样就创建了一个新的注解// 自定义注解 // Target 标注注解的注解叫做元注解 // ElementType.TYPE: 表示可以标注在类上 // ElementType.FIELD: 表示可以标注在属性上 // 使用某个注解的时候如果注解的属性名是value可以省略属性名 // 使用某个注解的时候如果注解的属性值是数组并且数组中只有一个值可以省略大括号 Target(value {ElementType.TYPE,ElementType.FIELD}) // Retention 标注注解的生命周期叫做元注解表示最终保留在class文件中并且可以被反射机制读取 // RetentionPolicy.SOURCE: 注解只在源码中存在编译成字节码后就不存在了 // RetentionPolicy.CLASS: 注解在源码和字节码中都存在运行时不存在默认值也就是不能被反射机制读取 // RetentionPolicy.RUNTIME: 注解在源码、字节码和运行时都存在 Retention(RetentionPolicy.RUNTIME) public interface Component { String value(); }怎么通过反射机制读取注解假设user类被注解Component修饰Component(userBean) public class User { }public static void main(String[] args) throws Exception { // 使用反射机制读取注解 // 获取类 Class? userClazz Class.forName(com.ali.component.User); // 判断类上是否有某个注解 boolean hasAnnotation userClazz.isAnnotationPresent(Component.class); if (hasAnnotation) { // 获取类上的注解对象 Component component userClazz.getAnnotation(Component.class); // 访问注解的属性 System.out.println(component value: component.value()); } }组件扫描原理主要是通过反射机制实例化注解标记的类的对象。public static void main(String[] args) { // 根据一个包名扫描这个包下面的所有类当这个类有Component注解时实例化这个类key是Component注解的valuevalue是实例化的对象 String packageName com.ali.component; // 将包名中的“.”替换成“/” String path packageName.replaceAll(\\., /); // 包是在系统恨路径下的一个目录。获取它的绝对路径 String absolutePath ClassLoader.getSystemClassLoader().getResource(path).getPath(); // 获取包下面的所有类文件 File dir new File(absolutePath); File[] files dir.listFiles(); Arrays.stream(files).forEach(file - { // 获取类名 String classname packageName . file.getName().replace(.class, ); // 通过反射机制解析注解 try { Class? clazz Class.forName(classname); // 判断类上是否有某个注解 boolean hasAnnotation clazz.isAnnotationPresent(Component.class); if (hasAnnotation) { // 获取类上的注解对象 Component component clazz.getAnnotation(Component.class); // 访问注解的属性 System.out.println(component value: component.value()); // 实例化这个类 Object obj clazz.getDeclaredConstructor().newInstance(); System.out.println(实例化对象: obj); } } catch (Exception e) { e.printStackTrace(); } }); }声明bean的注解声明bean的注解有Component 、Controller、 Service 、Repository。实际上 Controller Service Repository 这3个都是Component 的别名本质上就是一个注解。主要是为了增强代码的可读性。当这4个注解标注在类上是如果没有指定value值也就是没有指定bean名称那么bean名称默认成类名的首字母小写。选择性实例化bean假如有一个需求只需要Controller参与bean的管理。其他三个注解都不参与实例化这种情况要怎么处理注意别忘了添加配置文件的命名空间。!-- 第一种方案使用ComponentScan自动扫描bean use-default-filtersfalse 表示不使用默认的过滤器即所有声明bean的注解全部失效 Component 、Controller、 Service 、Repository 全部失效-- context:component-scan base-packagecom.ali.bean2 use-default-filtersfalse !-- 自定义过滤器指定只扫描带有Component注解的类 只有Component生效-- context:include-filter typeannotation expressionorg.springframework.stereotype.Component/ !-- 如果想让Service生效可以添加下面这一行-- context:include-filter typeannotation expressionorg.springframework.stereotype.Service/ /context:component-scan !-- 第二种方案use-default-filterstrue 或者不写该属性表示 Component 、Controller、 Service 、Repository 全部生效-- context:component-scan base-packagecom.ali.bean2 !-- 排除Controller注解的类 只有Controller生效-- context:exclude-filter typeannotation expressionorg.springframework.stereotype.Controller/ !-- 如果想让Repository失效可以添加下面这一行-- context:exclude-filter typeannotation expressionorg.springframework.stereotype.Repository/ /context:component-scan负责注入的注解valuevalue使用value注入的话属性可以不提供setter方法负责注入简单类型。public class User { Value(Alice) private String name; Value(22) private int age; }value注解也可以加在setter方法上public class User { private String name; private int age; Value(Alice) public void setName(String name) { this.name name; } Value(22) public void setAge(int age) { this.age age; } }value注解也可以加在构造方法上public class User { private String name; private int age; public User(Value(Alice) String name,Value(22) int age) { this.name name; this.age age; } }AutowiredAutowired可以用来注入非简单类型翻译为自动装配。单独使用 Autowired注解默认根据类型装配【默认是byType】注意假如一个接口被2个或以上的类实现那么这个接口对象能被 Autowired注入吗这当然不行因为 Autowired是根据类型进行装配的。那怎么解决这个问题呢可以将Autowired和Qualifier联合使用Autowired // 这里指定bean的名称说明是根据名称进行自动装配的 Qualifier(someServiceBeanForMysql) private SomeService someService;Autowired可以标注在属性上、setter方法上、构造方法的参数上。当一个类中的构造方法只有一个并且构造方法的参数和属性能对应上Autowired 可以省略不建议这样用ResourceResource注解也能完成非简单类型的注入那么他和 Autowired有什么区别呢Resource是jdk扩展包中的属于jdk的一部分所以该注解是标准注解更加具有通用性。Autowired是spring框架自己的Resource默认根据名称自动装配未指定name时使用属性名作为name如果通过name找不到的话。会启动通过类型自动装配。Autowired时根据类型自动装配。如果要根据名字装配需要Qualifier配合使用Resource用在属性上、setter方法上Autowired用在属性上、setter方法上、构造方法上、构造方法参数上。使用Resource时先加入相关依赖!-- Resource注解的依赖-- dependency groupIdjakarta.annotation/groupId artifactIdjakarta.annotation-api/artifactId version2.1.1/version /dependency// 进行属性注入 Resource(name someServiceBean) private SomeService someService;