之前是通过XML声明的方式将的Bean对象存储到Spring里面的,但是使用这种方式来把Bean存储到Spring中并不是很好:
1)需要手动添加每一个Bean对象到配置文件里面
2)如果说配置文件出现了问题,是不方便进行调试的
如果说配置文件出现了问题,是不会影响到程序的运行的,它不会像 抛异常一样,来 “显式” 的 打印 错误信息栈,描述具体的错误位置;
就是通过利用 注解,来简化存入,取出 Bean(对象)的步骤
一:创建Spring项目:
先进行创建maven项目,在pom.xml里面引入对Spring所依赖的jar包(核心包:5.2.3)
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.3.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.2.3.RELEASE</version> </dependency>
二:配置Spring的XML文件:
在resouces下面创建一个xml文件引入下面的这段代码
配置web.xml,进行设置spring存入对象的根路径也就是扫描路径,它的一个目的就是为了当Spring项目启动之后,可以去根路径下的所有类中扫描并将其标识为需要存储到Spring中的对象存储到Spring里面,还是在resource目录下进行创建XML文件
为了提高性能,而是不是让Spring容器去扫描所有指定的目录,只要在特定目录里面扫描和加上五大类注解才可以放到Spring容器里面;
如果不加扫描路径,那么Spring会扫描所有路径,那么效率就会变得非常的低
<?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"> <content:component-scan base-package="APP">//存储根路径 <!--把APP下面的类让Spring启动的时候都去扫描一下,配置Spring扫描的根路径, 此根路径下的所有的Spring存对象的注解才可以生效, 看看哪一个类需要存入到Spring里面--> 所有要存放到Spring容器的对象都放在这个根路径 </content:component-scan> </beans>
前置工作已经完成:成功的在Spring配置文件里面设置Bean的扫描根路径
三)五大类注解介绍
控制层+服务层+数据持久层
1)每一个类注解都对应着一次分层,五大类注解所负责的业务场景是不同的,它们对应的层级也不同;
2)为什么需要这么多类注解,主要原因就是说让我们的程序员看到这些类注解之后,直接了解到这些类的用途,就是让代码的可读性提高,让程序员直观地看到当前类的业务用途
1)Controller控制器:当前端访问后端的时候,首先就会先进入到控制器针对前端的访问参数做一个校验,如果参数检测不正确或者是一个非法请求,那么直接返回给前端不会进行处理业务只有Controller控制层的参数校验通过了才可以执行接下来的代码,前端参数校验
控制器用来校验用户请求数据的合法性,也就是安保系统,直接和前端打交道,校验前端的发来请求的参数是否合法
2)Service业务逻辑层:主要的功能就是根据业务常景来做数据组装和接口的调用的,假设你进行注册功能,我要向用户表里面添加一条数据,向日志表里面添加一条数据,就要在Service层调用两个接口,主要是服务编排,不会操作数据库,是根据请求来决定调用哪一个方法
3)Repository(仓库),数据持久化操作,数据存储层,进行数据保存和数据查询,会与数据库进行连接和交互,调用JDBC的驱动,数据库表的基本增删改查操作;
1)然后把查询数据向上传递,最终Controller把结果返回给前端,前端进行渲染,展示出页面效果;
2)这些注解主要就是为了让程序员看到注解之后,可以更好地了解到当前的类的用途,代码的可读性提高,也就是让程序员更好的看到这些类的业务用途3)前后端交互更详细的流程:
3.1)前端来的所有的数据都会首先到达Controller层,针对我们的前端参数进行校验
3.2)校验通过之后,会到达服务层,然后服务层会去分配接口,分配了接口之后才会在数据
3.3)在数据持久层里面操作数据库,肯定是为了操作某一些数据;
3.4)数据持久层就会先把数据返回给服务层,服务层拿到数据库返回的数据进行组装,返回给Controller层
4)@Configuration(配置)配置系统的配置信息,当前实际业务项目中所有的配置,我们都要建一个新的包,把所有的配置信息全部放在这一个包里面,当我们进行修改配置,维护配制的时候,只需要在这一层找就可以了,配置拦截器就在这个层;
5)@Component(组件):公共的工具类,没有办法把它放到其他任何一个的层里面,所以就把它放到这个注解;
1)方法注解必须配合类注解进行使用
Spring上下文对象.getBean("类名(首字母小写或者是正常的类名)",类名.class);
Spring上下文对象.getBean("方法名",方法返回对象的返回值)
Spring上下文对象.getBean("id名字",类对象)
2)当我们已经通过配置扫描路径和注解添加到类名上面来进行更简单的存储Bean对象之后,我们还要想办法来进行获取到这个类对象;
3)我们在这里面还是想要通过传统的通过Spring上下文的方式来进行获取到Bean对象;
4)类名首字母和第二个字母都是非大写,那么通过GetBean()方法的时候需要通过类名来进行获取到Bean对象的时候,类名就不能使用原来的类名了,而是通过类名首字母小写的方式来进行获取到bean;
5)如果说首字母和第二个字母都是大写况且名字的长度大于1,那么直接使用原Bean名,来进行获取,不满足这个条件,就让原Bean名首字母小写;
1)读取存入对象的id:默认情况下是首字母小写;
2)关于存储目录:所有需要存储到Spring框架中的对象的目录,必须在Spring配置文件(XML)文件配置的目录下,component-scan目录下,存入到Spring里面的内容是一个键值对:
3)GetBean(Key值是被注解修饰过的类名的首字母的小写形式,Value就是类名);
像这样在扫描路径下创建类,并在类上加上
@Controller
注解就将Bean
存储到容器当中了
下面我们来演示一下:如何使用五大类注解将对象存储到Spring容器里面
存入:通过包扫描路径+五大类注解来进行把对象存储到Spring容器里面
取出:通过Spring的上下文对象来进行取出:
使用Controller注解和Component注解:
1)在配置文件里面配置SpringIOC容器的扫描路径
2)在要存入的SpringIOC容器的Bean对象中加上五大类注解
3)在启动类中获取到存储到IOC容器的Bean对象,在这里面还是通过GetBean来进行获取
如果说给当前类没有加上五大类注解或者是说扫描路径错误,那么此时就会导致异常:
生成beanname的源码?
使用方法注解@Bean将对象更加简单的存储到IOC容器里面:
主要目的就是把方法返回的对象存储到Spring里面:
1)GetBean(方法名称,方法返回值的class也就是类对象)
2)注意事项:Spring默认情况下是类扫描,默认是类注解而不是方法注解,因此如果使用的是方法注解@Bean,那么就必须要配合类注解进行使用,这个类注解可以是五大类注解任意一个,通常情况下就是搭配@Component组件和Bean一块进行使用才可以将方法返回对象存储到Spring里面;
@Component
public class GetBean {
@Bean(name ="u1")//将当前User对象存储到Spring里面
public User GetUser(){
User user=new User();
user.setId(1);
user.setName("李佳伟");
return user;
}
}
//这时候可以进行不关注方法名
ApplicationContext context=new ClassPathXmlApplicationContext("web.xml");
User user=context.getBean("u1",User.class);
1)但是我们在方法的返回值上面写了@Bean(name = "u1")之后,再写这个代码就会发生报错,User user=context.getBean("GetUser",User.class);
2)当我们没有在@Bean注解指定name属性的时候,我们是完全BeanName的值就是方法的名字,但是我们如果指定了name的名字,我们就只能通过这个name名字来进行获取到存储在Spring中的对象了;
四)@Bean注解+使用方法注解存储Bean对象
1)为了减少扫描的范围,增加框架加载速度,即使你已经在方法注解上面加了bean,你还要在这个方法所在的类上面配合5大类注解进行使用,这样才可以将一个方法的返回值对象存储到Spring中,如果你只写了方法注解而没有在类上面写类注解,那么这个时候方法返回的对象是不能存放在Spring里面的;
2)为了获取这个返回的对象,Bean的名字使用的是方法名,方法返回值的类对象,而不是通过大驼峰的方式来进行获取;
3)此时想要获取@Bean修饰方法的返回值,也是可以只通过类对象来进行获取的,只是不过和之前的规则一样相同的Bean注入会报错;
当使用方法注解来进行存储所使用的对象的时候,传入的BeanName就是方法名
1)使用@Bean注解来将到方法返回对象注册到Spring里面,这里面的ID就变成了方法名,我们仍然可以通过传统的方式来进行获取到这个Bean对象:
获取方法注解存储的对象的时候,传入的BeanName参数值默认是方法名,但是像上面那样BeanName使用的是方法名字太别扭了,虽然在语法和实现上没有任何问题,但是开发中写出这样的代码还是比较别扭的,实际上@Bean是可以加参数的,给存储的对象起别名,那么下次再进行取出对象的时候,就可以不使用方法名而是使用别名来取出我们需要存储的对象,但是当使用别名以后再次使用方法名来充当BeanName是无法获取到Bean对象的
//方式一(省略参数名的情况下默认是name) @Bean("article1") //方式二 @Bean(name = "article2") //方式三 @Bean(value = "article3") //起多个别名 @Bean(name = {"article4", "article5"}) @Bean(value = {"article6", "article7"}) @Bean({"article8", "article9", "article10"})
2)使用类名.class的方式来进行尝试获取返回值,也就是已经存到Spring中的返回值对象,当多个不同的方法的返回值相同的时候,就会发生报错;
我们的这个User对象只能在Spring对象中注入一次,也就是说当我有两个方法都是返回的User对象的时候,这个用类对象来获取就不灵了;
User里面的代码: package APP; public class User { public String username; public String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "username='" + username + '\'' + ", password='" + password + '\'' + '}'; } }
@Controller public class UserDemo { @Bean public User GetUser1(){ User user=new User(); user.username="李佳伟"; user.password="12503487"; return user; } @Bean public User GetUser2(){ User user=new User(); user.username="李嘉欣"; user.password="178"; return user; } }
当进行运行上述代码的时候,会出现报错,仔细想一想也是,当多个方法的返回值都是User的时候,你的程序只是想通过User.class获取,此时会返回多个User对象呀;
解决方法:@Bean存储多个相同的类的对象的报错问题
1)通过ID也就是固定方法名称和类名或者只通过ID来进行获取:
User user1=context.getBean("GetUser1",User.class); User user2=context.getBean("GetUser2",User.class);
2)使用特殊的注解方法:况且之前的用方法名的写法看起来就很别扭,你说获取到Bean对象要写方法的名字,这样就很不好,所以我们通过下面的方式来进行更简单的获取到@Bean修饰方法的返回值,不修改方法名称的情况下就通过设置name属性来进行解决,下面可以设置多个名字
public class User { public String username; public String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "username='" + username + '\'' + ", password='" + password + '\'' + '}'; } }
@Controller public class UserDemo { @Bean(name = "u1") public User GetUser1(){ User user=new User(); user.username="李佳伟"; user.password="12503487"; return user; } @Bean(name = "u2") public User GetUser2(){ User user=new User(); user.username="李嘉欣"; user.password="178"; return user; } }
public static void main(String[] args) { //1.先进行获取到Spring的上下文对象 ApplicationContext context=new ClassPathXmlApplicationContext("web.xml"); //2.在进行获取到Bean对象 User users= (User) context.getBean("u1"); //3.打印Bean对象 System.out.println(users); }