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的依赖
还是第一步,通过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(); } }
-
-
- @Repository
- @Service
- @Controller
- @Compoent