Spring IoC注解式开发无敌详细(细节丰富)

慈云数据 2024-05-09 技术支持 97 0

1. Spring IoC注解式开发无敌详细(细节丰富)

文章目录

  • 1. Spring IoC注解式开发无敌详细(细节丰富)
  • 每博一文案
  • 2. 注解回顾
  • 3. Spring 声明Bean的注解
    • 3.1 Spring注解的使用
      • 3.1.1 特别的:如果要扫描的是多个包
      • 3.1.2 Spring 选择性实例化Bean对象
      • 3.2 通过注解实现“Spring的注入”
        • 3.2.1 @Value 注解的 Bean 赋值
        • 3.2.2 @Autowired 与 @Qualifier
        • 3.2.3 @Resource 注解实现赋值操作
        • 3.3 Spring 全注解式开发
        • 4. 总结:
        • 5. 疑问:
        • 6. 最后:

          每博一文案

          读书,它可以在我生活顺遂的时候,看见更大的世界,
          在生活不顺的时候,依然可以有心态去仰望星空。
          无论如果都不要将爱,转为成了某种恨
          就是我过的不好,也希望你过的好,就算我过的不好,我也依旧会帮你过的好
          不管你一天,经历了什么,天黑了,我带你回家。
          生命是有光的,在我熄灭已前,能够照亮你一点便是,我所有能做的了。
          

          2. 注解回顾

          既然我们要学习:”Spring IoC注解式开发“,自然就是要是用上注解 的,为了方便后面的学习,这里我们简单回顾一下注解的内容。更多关于注解方面的内容大家可以移步至:✏️✏️✏️ Java “框架 = 注解 + 反射 + 设计模式” 之 注解详解-CSDN博客 。

          import java.lang.annotation.ElementType;
          import java.lang.annotation.Retention;
          import java.lang.annotation.RetentionPolicy;
          import java.lang.annotation.Target;
          @Target(value = {ElementType.TYPE})
          @Retention(value = RetentionPolicy.RUNTIME)
          public @interface Component {
              String value();
          }
          

          以上是自定义了一个注解:Component

          该注解上面修饰的注解包括:Target注解和Retention注解,这两个注解被称为元注解。

          Target注解用来设置Component注解可以出现的位置,以上代表表示Component注解只能用在类和接口上。

          Retention注解用来设置Component注解的保持性策略,以上代表Component注解可以被反射机制读取。

          String value(); 是Component注解中的一个属性。该属性类型String,属性名是value。

          注解赋值 ——》语法格式:@注解类型名(属性名=属性值, 属性名=属性值, 属性名=属性值…)

          userBean为什么使用双引号括起来,因为value属性是String类型,字符串

          另外如果属性名是value,则在使用的时候可以省略属性名。

          为了进一步,运用注解,这里我们看看下面这个需求。

          目前只知道一个包com.rianbowsea 的名字,扫描这个包下所有的类,当这个类上有@Compoent 注解的时候,实例化该对象,然后放到Map集合中。

          在这里插入图片描述

          在这里插入图片描述

          在这里插入图片描述

          package com.rainbowsea;
          import java.lang.annotation.ElementType;
          import java.lang.annotation.Retention;
          import java.lang.annotation.RetentionPolicy;
          import java.lang.annotation.Target;
          // 使用某个注解的时候,如果注解的属性值是数组,并且数组中只有一个元素,大括号可以省略。
          @Target(ElementType.TYPE)
          // @Retention 也是一个元注解,用来标注@Component 注解最终保留在class 文件当中,并且可以被反射机制读取
          @Retention(RetentionPolicy.RUNTIME)
          public @interface Component {
              // 定义注解的属性
              // String 是属性类型
              // value 是属性名
              String value();
          }
          
          package com.rainbowsea;
          //
          //@Component(value = "userBean",属性名 = 属性值,属性名 = 属性值,属性名 = 属性值...)
          //@Component(value = "userBean")
          // 如果属性名是 value,value 可以省略
          @Component("userBean")
          public class User {
          }
          
          package com.rainbowsea;
          @Component("orderBean")
          public class Order {
          }
          

          在这里插入图片描述

          在这里插入图片描述

          package com.rainbowsea;
          import java.io.File;
          import java.lang.reflect.Constructor;
          import java.lang.reflect.InvocationTargetException;
          import java.net.URL;
          import java.util.Arrays;
          import java.util.HashMap;
          import java.util.Map;
          public class ComponentScan {
              /*
              目前只知道一个包的名字,扫描这个包下所有的类,当这个类上有@Compoent 注解的时候,
              实例化该对象,然后放到Map集合中
               */
              public static void main(String[] args) {
                  //定义一个集合存储其中的实例化对象
                  Map beanMap = new HashMap();
                  String packageName = "com.rainbowsea";
                  // 开始扫描程序
                  // .这个正则表达式表示任意字母,这里的“.” 必须是一个普通的"."字符,不能是正则表达式中的“.”
                  // 在正则表达式当中怎么表示一个普通的"." 字符呢?使用"\",在Java当中一个“/” 要用两个“//” 表示
                  String packagePath = packageName.replaceAll("\\.", "/");
                  //System.out.println(packagePath);
                  // com 是在类的根路径下的一个目录
                  //  url 是一个绝对路径
                  URL url = ClassLoader.getSystemClassLoader().getResource(packagePath);
                  String path = url.getPath();
                  //System.out.println(path);
                  // 获取一个绝对路径下的所有文件
                  File file = new File(path);
                  File[] files = file.listFiles();
                  Arrays.stream(files).forEach(file1 -> {
                      //System.out.println(file1);
                      //System.out.println(file1.getName().split("\\.")[0]);
                      // 拼接成:全限定类名
                      String className = packageName + "." + file1.getName().split("\\.")[0];
                      // 再通过反射机制,解析注解
                      Class aClass = null;
                      try {
                          aClass = Class.forName(className);
                      } catch (ClassNotFoundException e) {
                          throw new RuntimeException(e);
                      }
                      // 判断该类是否含有该 Component.class 注解
                      if(aClass.isAnnotationPresent(Component.class)) {
                          // 获取注解
                          Component annotation = aClass.getAnnotation(Component.class);
                          // 获取到该注解的值
                          String id = annotation.value();
                          // 有这个注解的都要创建对象
                          try {
                              Constructor declaredConstructor = aClass.getDeclaredConstructor();
                              Object obj  = declaredConstructor.newInstance();
                              // 将创建好的实例化对象存储到 Map 当前去。
                              beanMap.put(id,obj);
                          } catch (Exception e) {
                              e.printStackTrace();
                              throw new RuntimeException(e);
                          }
                      }
                  });
                  System.out.println(beanMap);
              }
          }
          

          运行结果

          在这里插入图片描述

          3. Spring 声明Bean的注解

          注解的存在主要是为了简化XML的配置。Spring6倡导全注解开发。

          在Spring 当中,负责声明 Bean 的注解的,常见的有如下四个:

          • @Compoent

            在这里插入图片描述

            • @Controller

              在这里插入图片描述

              • @Service

                在这里插入图片描述

                • @Repository

                  在这里插入图片描述

                  通过源码可以看到,@Controller、@Service、@Repository 这三个注解都是@Component注解的别名。换句话说:这四个注解的功能都一样。用哪个都可以。

                  只是为了增强程序的可读性,建议:

                  • 控制器类上使用:Controller

                  • service类上使用:Service

                  • dao类上使用:Repository

                    他们都是只有一个value属性。value属性用来指定bean的id,也就是bean的名字

                    在这里插入图片描述

                    3.1 Spring注解的使用

                    如何使用以上的注解呢?

                      • 第一步:加入aop的依赖
                        • 第二步:在配置文件中添加context命名空间
                          • 第三步:在配置文件中指定扫描的包
                            • 第四步:在Bean类上使用注解

                    第一步:加入aop的依赖

                    还是第一步,通过Maven 导入相关的 jar 包,在 pom.xml 文件当中。

                    
                        4.0.0
                        com.rainbowsea.reflect
                        spring6-oo8-anotation-blog
                        1.0-SNAPSHOT
                        
                            17
                            17
                        
                        
                            
                                org.springframework
                                spring-context
                                6.0.11
                            
                            
                            
                                junit
                                junit
                                4.13.2
                                test
                            
                            
                                jakarta.annotation
                                jakarta.annotation-api
                                2.1.1
                            
                        
                    
                    

                    我们可以看到当加入spring-context依赖之后,会关联加入aop的依赖。所以这一步不用做。

                    在这里插入图片描述

                    第二步:在配置文件中添加context命名空间

                    注意:这里所说的配置文件是指,我们配置 bean 对象的那个配置.xml 的配置文件信息。如下:

                    在这里插入图片描述

                    
                    
                    

                    第三步:在配置文件中指定扫描的包

                    注意:这里所说的配置文件是指,我们配置 bean 对象的那个配置.xml 的配置文件信息。如下:

                    指定扫描的包: 是指明Spring 在那个包路径下,可以找到要实例化的 Bean 对象。

                    在这里插入图片描述

                    在这里插入图片描述

                        
                    
                    
                    
                        
                    
                    

                    第四步:在Bean类上使用注解

                    如下:上面四个注解(@Controller、@Service、@Repository @Component),我们都使用测试上,看看能否实例化成功。

                    在这里插入图片描述

                    在这里插入图片描述

                    package com.rainbowsea.reflect.sprint.bean;
                    import org.springframework.stereotype.Service;
                    //@Service(value = "orderBean")
                    @Service("os")
                    public class Order {
                    }
                    
                    package com.rainbowsea.reflect.sprint.bean;
                    import org.springframework.stereotype.Repository;
                    @Repository("studentBean")
                    public class Student {
                    }
                    /**
                     * 以上的 @Repository就相当域以下的配置信息
                     * 
                     */
                    
                    package com.rainbowsea.reflect.sprint.bean;
                    import org.springframework.stereotype.Component;
                    @Component(value = "userBean")
                    public class User {
                    }
                    
                    package com.rainbowsea.reflect.sprint.bean;
                    import org.springframework.stereotype.Controller;
                    @Controller(value = "vipBean")
                    public class Vip {
                    }
                    

                    在这里插入图片描述

                    package com.rainbowsea.test;
                    import com.rainbowsea.reflect.sprint.bean.Order;
                    import com.rainbowsea.reflect.sprint.bean.Student;
                    import com.rainbowsea.reflect.sprint.bean.User;
                    import com.rainbowsea.reflect.sprint.bean.Vip;
                    import org.junit.Test;
                    import org.springframework.context.ApplicationContext;
                    import org.springframework.context.support.ClassPathXmlApplicationContext;
                    public class IoCAnnotationTest {
                        @Test
                        public void testIoCAnnotation() {
                            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
                            Order os = applicationContext.getBean("os", Order.class);
                            System.out.println(os);
                            Student studentBean = applicationContext.getBean("studentBean", Student.class);
                            System.out.println(studentBean);
                            User userBean = applicationContext.getBean("userBean", User.class);
                            System.out.println(userBean);
                            Vip vipBean = applicationContext.getBean("vipBean", Vip.class);
                            System.out.println(vipBean);
                        }
                    }
                    

                    3.1.1 特别的:如果要扫描的是多个包

                    特别的: 如果要扫描的是多个包

                    • 如果你要配置,扫描多个包下的文件可以使用逗号分隔开来 。
                    • 或者是上一级一些,不过,可能会牺牲一点效率,查找的时间上多一些。在这里插入图片描述
                          
                      
                      
                          
                          
                      
                      

                      测试:

                      在这里插入图片描述

                      在这里插入图片描述

                      或者是上一级一些,不过,可能会牺牲一点效率,查找的时间上多一些。如下:

                      在这里插入图片描述

                          
                          
                      
                      
                          
                          
                      
                      

                      在这里插入图片描述


                      3.1.2 Spring 选择性实例化Bean对象

                      假设在某个包下有很多Bean,有的Bean上标注了@Component,有的标注了@Controller,有的标注了@Service,有的标注了@Repository,现在由于某种特殊业务的需要,只允许其中所有的Controller参与Bean管理,其他的都不实例化。这应该怎么办呢?

                      我们可以有一下两种方案:

                      第一种方案:

                      在扫描文件的: 的标签当中添加上:use-default-filters=" 属性,并该属性指为 false 。表示该表明的包下的所有带有声明Bean (@Component,@Controller,@Service,@Repository)的注解全部失效。不会实例化该包下的 bean 对象。

                      • 在这里插入图片描述

                        而只有在 的标签下的,指明的: 说明的注解才会生效,才会实例化该包下的 Bean 对象。注意其中的值是:include-filter,type=“annotation”,expression=“org.springframework.stereotype.Controller” 注意:这个包名路径不要错了。org.springframework.stereotype.Controller

                        在这里插入图片描述

                        
                            
                            
                            
                                
                            
                        
                        
                        • 测试:这里我们让注解是:@Service,@Controller 的这个两个有效,实例化Bean 对象,其他的注解失效,不实例化Bean 对象。

                          在这里插入图片描述

                          在这里插入图片描述

                              
                                  
                                  
                              
                          
                          
                              
                              
                              
                                  
                                  
                              
                          
                          

                          运行测试:

                          在这里插入图片描述

                          第二种方案:

                          use-default-filters=" 属性,并该属性指为 true (为true 值是默认的,可以省略不写)。表示该表明的包下的所有带有声明Bean (@Component,@Controller,@Service,@Repository)的注解全部生效。会实例化该包下的 bean 对象。

                          在这里插入图片描述

                          而在 的标签下的,指明的: @Test public void testIoCAnnotation() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring2.xml"); User userBean = applicationContext.getBean("userBean", User.class); System.out.println(userBean); } } this.name = name; this.age = age; this.vip = vip; } void insert(); } @Override public void insert() { System.out.println("MySQL数据库正在保存订单信息"); } } private OrderDao orderDao ; @Autowired public void setOrderDao(OrderDao orderDao) { this.orderDao = orderDao; } public void generate() { orderDao.insert(); } } this.orderDao = orderDao; } this.orderDao = orderDao; } this.orderDao = orderDao; } this.orderDao = orderDao; } "com.rainbowsea.reflect.sprint.bean","com.rainbowsea.reflect.sprint.dao"}) public class Spring6Configuration { } public void testIoCAnnotation() { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Spring6Configuration.class); OrderService orderService = applicationContext.getBean("orderService", OrderService.class); orderService.generate(); } }

微信扫一扫加客服

微信扫一扫加客服

点击启动AI问答
Draggable Icon