欢迎阅读~
目录
2.6.3使用@Autowired+@Qualifier来筛选Bean对象
1.存储Bean对象
前面我们学习了在存储一个Bean对象时,可以在Spring-config中添加一行bean注册内容。然而,当我们需要创建多个Bean对象时,就需要添加多行,类似于下面的代码:
显然,这是非常麻烦的,所以我们引入了下面所说的配置扫描路径。
1.1前置工作:配置扫描路径
①配置扫描路径为的目的:
注意:想要将对象成功的存储到 Spring 中,我们需要配置一下储对象的扫描包路径,只有被配置的包下的所有类,添加了注解才能被正确的识别并保存到 Spring 中。②我们需要在Spring-config中配置好扫描路径的xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:content="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- 配置spring扫描的根路径(此根路径下的所有spring存对象的注解才能生效)--> <content:component-scan base-package="这里写自己的包名,如:com.bean"> </content:component-scan> </beans>
③注意:必须保证添加的注解配置于扫描的包下,否则也是不能被存储到spring中的。
1.2五大注解的方式存储Bean对象
要想通过注解的方式将对象存于spring中,主要有两种方法,其一是通过类注解中的五大注解进行存入,其二是通过方法注解@Bean来进行存入。下面我们先来介绍五大注解存入。
@Controller(控制器存储)
①使用@Controller存入的代码如下:
package inBean; import org.springframework.stereotype.Controller; @Controller public class UserController { public void run(){ System.out.println("这是@Controller"); } }
主函数代码如下:
import inBean.UserController; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { public static void main(String[] args) { ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml"); UserController userController=context.getBean("userController",UserController.class); userController.run(); } }
此时的运行结果:
②运行原理:
当main函数开始执行扫描了spring-config.xml后,如果没有在UserController里面加注解的话,其就没有被注入到spring中,自然就不会读取到,这个时候就会抛出异常如下:
即在spring中没有此controller。
@Service(服务存储)
①通过@service存入代码如下:
package inBean; import org.springframework.stereotype.Service; @Service public class UserService { public void run(){ System.out.println("这是@Service"); } }
main函数代码如下:
import inBean.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { public static void main(String[] args) { ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml"); UserService service=context.getBean("userService",UserService.class); service.run(); } }
结果如下:
②运行原理:
同@Controller理所解释的,故不再重复
@Repository(仓库存储)
①通过@Repository存入代码如下:
package inBean; import org.springframework.stereotype.Repository; @Repository public class UserRepository { public void run(){ System.out.println("这是@Repository"); } }
main函数代码如下:
import inBean.UserRepository; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { public static void main(String[] args) { ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml"); UserRepository userRepository=context.getBean("userRepository",UserRepository.class); userRepository.run(); } }
结果如下:
②运行原理:
同@Controller理所解释的,故不再重复
@Component(组件存储)
①通过@Component存入代码如下:
package inBean; import org.springframework.stereotype.Component; @Component public class UserComponent { public void run(){ System.out.println("这是@Component"); } }
main函数代码如下:
import inBean.UserComponent; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { public static void main(String[] args) { ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml"); UserComponent userComponent=context.getBean("userComponent",UserComponent.class); userComponent.run(); } }
结果如下:
②运行原理:
同@Controller理所解释的,故不再重复
@Configuration(配置存储)
①通过@service存入代码如下:
package inBean; import org.springframework.context.annotation.Configuration; @Configuration public class UserConfiguration { public void run(){ System.out.println("这是@Configuration"); } }
main函数代码如下:
import inBean.*; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { public static void main(String[] args) { ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml"); UserConfiguration userConfiguration=context.getBean("userConfiguration",UserConfiguration.class); userConfiguration.run(); } }
结果如下:
②运行原理:
同@Controller理所解释的,故不再重复
1.2.1为什么需要五大类注解
根据以上五大注解的示例,可能大家会觉得这样看来它们的功能几乎一致,那为什么还要五大注解呢?因为其实每个注解的含义是 不一样的,我们要做的是看到注解,能够知道这段代码主要是干嘛的。
①需要五大类注解的原因:
实质上是增加了代码的可读性
②五大注解的含义及应用图例:
这个就是我们前后端实现交互的过程,我们在配置好了之后,前端通过传入参数到控制层进行校验,校验完成后,将其传入服务层,接着由服务层将其传到数据持久层,数据持久层就会和数据库里的内容进行交互,然后再依次往上传到控制层后返回给前端。
1.2.2这五大类注解之间有什么关系
①关系:
可以认为是父类子类的问题
②原因:(图解)
1.3通过@Bean方法注解存储对象
①什么是方法注解:
方法注解是放于某个方法上的注解
②示例:
a.重写user类的代码:
package inBean; public class User { private int id; private String name; private int age; @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
b.UserBean类的代码:
package inBean; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Controller; @Controller public class UserBean { @Bean public User user(){ User user=new User(); user.setAge(20); user.setId(1); user.setName("张三"); return user; } }
c.main代码:
import inBean.*; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { public static void main(String[] args) { ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml"); User user=context.getBean("user",User.class); System.out.println(user); } }
③方法注解相对于类注解的优点:
方法注解的范围精确更小,可以说是开销更小一点。
④注意:
(1)方法注解必须加上类注解,否则抛出异常:
(2) 对于方法注解的重命名问题:
a.要是方法注解没有进行重命名,那么此时的名字就应该是方法名
b.可以通过设置 name 属性给 Bean 对象进行重命名操作:
命名后需要根据重命名的来进行获取 否则会报错。
2.获取Bean对象
这一系列操作都是为了将对象从容器中拿出来。是把对象取出来放到某个类中。
2.1属性注入
①属性注入实现的关键:
使用@Autowired
②举例:将Service类注入到Controller类中。
(1)@Service类代码:
package inBean; import org.springframework.stereotype.Service; @Service public class UserService { public void run(){ System.out.println("这是用来实现属性注入的"); } }
(2)@UserController类代码:
package inBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; @Controller //表示将当前的类注册到Spring当中 public class UserController { //1.属性注册 从Spring中获取一个对象,并注入到当前类(将UserService注入到UserController中) @Autowired private UserService userService; public void run(){ userService.run(); } }
(3)main代码:
import inBean.*; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { public static void main(String[] args) { //1.先获取对象的上下文 ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml"); //方式一 UserController controller = context.getBean("userController", UserController.class); controller.run(); } }
输出结果:
③重点含义理解:
我们告诉Spring当前的类,在加载①这个类的时候,首先先将UserService对象注入到当前这个类的userService属性里面。前提条件是Spring中已经有UserService被注入进去了。因此这就是通过②将属性注入到①中。而我们之前注入需要得到上下文对象,然后getBean(),然后取,现在一个@Autowired就解决了。
2.2构造方法注入
①仍然是以注入UserService为例来举例:
(1)@controller代码:
package inBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; @Controller public class UserController3 { private UserService userService; @Autowired public UserController3(UserService userService){ this.userService=userService; } public void run(){ userService.run(); } }
(2)main:
package inBean; import org.springframework.stereotype.Service; @Service public class UserService { public void run(){ System.out.println("这是用来实现构造方法注入的"); } }
②注意:
当一个类中只有一个构造方法时,@Autowied注解可以省略,就像上面的代码中一样,是可以省略的。而当存在多个构造方法时,是不能够省略的,否则就会报错。如下图:
因为它不知道究竟是要注入到哪个构造方法里面去。
③重点讲解:
当执行这个类的时候,就会触发它的构造方法,而UserService的属性userService已经存入spring中,就会将其属性赋给②,从而进行后面的其它操作。
2.3Setter注入
①仍然在UserService的基础上来进行注入实现:
(1)@Controller代码:
package inBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; @Controller public class UserController3 { private UserService userService; @Autowired public void setUserService(UserService userService){ this.userService=userService; } public void run(){ userService.run(); } }
(2)main:
import inBean.*; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { public static void main(String[] args) { //1.先获取对象的上下文 ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml"); //方式一 UserController3 userController3=context.getBean("userController3",UserController3.class); userController3.run(); } }
结果如下:
以上三种注入之间那么它们的区别是什么呢?
①属性注入:
写法非常简单的,但是通用性不好,只能运行在IoC容器下,如果在非IoC容器下,是很有可能空指针异常的。
②setter注入:早期Spring版本推荐的写法是Setter写法,但是Setter注入通用性没有构造方法注入通用。
③构造方法注入:Spring推荐的注入方式,它的缺点是如果有多个注入会显得比较臃肿,但出现这种情况你应该考虑一下当前类是否符合程序的单一职责的设计模式了,它的优势在于通用性更好,它能保证在使用注入对象之前,此注入对象一定是初始化过了的。
2.4注入另一种@Resource关键字
①@Resource关键字适用情况:
类似于和@Autowired的用法,可用于对象的注入,但是与@Autowired又有着一定的区别。
②区别与联系:
(1)来源不同:
@Autowired 来自于 Spring框架的注解,而 @Resource 是来自于 JDK 的注解。
(2)用法不同:@Autowired 支持属性注入,构造方法注入,Setter注入,而@Resource是不支持构造方法注入的。
(3)支持的参数不同:
@Resource支持更多的参数设置,比如name、type设置,而@Autowired只支持required参数设置。
2.5Bean重命名
这个的话,主要是命名规则:(下面是通过源码进行分析的结果,我们直接用就好)
①类注解命名:
通常我们Bean使用的都是标准的大驼峰命名,而读取的时候首字母小写就可以获取到 bean 了;但是当首字母和第二个字母都是大写时,上面的命名规则就不能正常读取到 bean 了,这时就需要直接用类名命名就可以获取到bean了。
②@Bean方法命名:
这个前面已经讲过,要是@Bean没有重命名过,那么这个时候的名称就是方法名,要是需要重命名的话就在上面加上参数@Bean(name={这里可有多个名字,但是指的却是同一个对象})
2.6@Bean将一个参数的类型注入多次
①@Bean将一个参数类型注入多次的后果:
报错,因为此时就是非唯一的Bean对象
②示例:
代码综合如下:
package inBean; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; @Component public class Users { @Bean public User user1(){ User user=new User(); user.setName("张三"); user.setId(1); return user; } @Bean public User user2(){ User user=new User(); user.setName("李四"); user.setId(2); return user; } } package inBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; @Controller public class UserController4 { @Autowired private User user; public User getUser(){ return user; } } import inBean.*; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test { public static void main(String[] args) { //1.先获取对象的上下文 ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml"); //方式一 UserController4 userController4=context.getBean("userController4",UserController4.class); userController4.getUser(); } }
结果如下:
2.6.1精确地描述Bean名称
①如何操作:
可以将注入的bean的名字修改成自己设定的name值
②示例:
此时输出结果:(注意!改名字被使用后,就不能再使用了)
2.6.2使用@Resource来重命名注入
①方法:
使用@Resource(name="user 1 ") 定义。②示例:我们就指明了取的是user1,那么这个时候结果如下:
2.6.3使用@Autowired+@Qualifier来筛选Bean对象
①操作:
因为@Autowired是没有name参数属性的,所以我们这里借助@Qualifier来共同实现筛选
②示例:
输出结果:
这一期到此结束,下期我们将讲Bean作用域相关知识。