Spring6详细教程(四)--->Spring IoC注解式开发

简介: 本章节有一下内容:Spring IoC注解式开发、JdbcTemplate的回顾

十二、Spring IoC注解式开发
12.1 回顾注解
注解的存在主要是为了简化XML的配置。Spring6倡导全注解开发。
我们来回顾一下:
第一:注解怎么定义,注解中的属性怎么定义?
第二:注解怎么使用?
第三:通过反射机制怎么读取注解?
注解怎么定义,注解中的属性怎么定义?
以上是自定义了一个注解:Component
该注解上面修饰的注解包括:Target注解和Retention注解,这两个注解被称为元注解。
Target注解用来设置Component注解可以出现的位置,以上代表表示Component注解只能用在类和接口上。
Retention注解用来设置Component注解的保持性策略,以上代表Component注解可以被反射机制读取。
String value(); 是Component注解中的一个属性。该属性类型String,属性名是value。
注解怎么使用?
用法简单,语法格式:@注解类型名(属性名=属性值, 属性名=属性值, 属性名=属性值......)
userBean为什么使用双引号括起来,因为value属性是String类型,字符串。
另外如果属性名是value,则在使用的时候可以省略属性名,例如:
通过反射机制怎么读取注解?
接下来,我们来写一段程序,当Bean类上有Component注解时,则实例化Bean对象,如果没有,则不实例化对象。
我们准备两个Bean,一个上面有注解,一个上面没有注解。
假设我们现在只知道包名:com.powernode.bean。至于这个包下有多少个Bean我们不知道。哪些Bean上有注解,哪些Bean上没有注解,这些我们都不知道,如何通过程序全自动化判断。
执行结果:


12.2 声明Bean的注解
负责声明Bean的注解,常见的包括四个:
@Component
@Controller
@Service
@Repository
源码如下:
通过源码可以看到,@Controller、@Service、@Repository这三个注解都是@Component注解的别名。
也就是说:这四个注解的功能都一样。用哪个都可以。
只是为了增强程序的可读性,建议:
控制器类上使用:Controller
service类上使用:Service
dao类上使用:Repository
他们都是只有一个value属性。value属性用来指定bean的id,也就是bean的名字。


12.3 Spring注解的使用
如何使用以上的注解呢?
第一步:加入aop的依赖
第二步:在配置文件中添加context命名空间
第三步:在配置文件中指定扫描的包
第四步:在Bean类上使用注解
第一步:加入aop的依赖
我们可以看到当加入spring-context依赖之后,会关联加入aop的依赖。所以这一步不用做。


第二步:在配置文件中添加context命名空间
第三步:在配置文件中指定要扫描的包
第四步:在Bean类上使用注解
编写测试程序:
执行结果:


如果注解的属性名是value,那么value是可以省略的。
执行结果:


如果把value属性彻底去掉,spring会被Bean自动取名吗?会的。并且默认名字的规律是:Bean类名首字母小写即可。
也就是说,这个BankDao的bean的名字为:bankDao
测试一下
执行结果:


我们将Component注解换成其它三个注解,看看是否可以用:
执行结果:


剩下的两个注解大家可以测试一下。
如果是多个包怎么办?有两种解决方案:
第一种:在配置文件中指定多个包,用逗号隔开。
第二种:指定多个包的共同父包。
先来测试一下逗号(英文)的方式:
创建一个新的包:bean2,定义一个Bean类。
配置文件修改:
测试程序:
执行结果:


我们再来看看,指定共同的父包行不行:
执行测试程序:


12.4 选择性实例化Bean
假设在某个包下有很多Bean,有的Bean上标注了Component,有的标注了Controller,有的标注了Service,有的标注了Repository,现在由于某种特殊业务的需要,只允许其中所有的Controller参与Bean管理,其他的都不实例化。这应该怎么办呢?
我只想实例化bean3包下的Controller。配置文件这样写:
use-default-filters="true" 表示:使用spring默认的规则,只要有Component、Controller、Service、Repository中的任意一个注解标注,则进行实例化。
use-default-filters="false" 表示:不再spring默认实例化规则,即使有Component、Controller、Service、Repository这些注解标注,也不再实例化。
表示只有Controller进行实例化。
执行结果:


也可以将use-default-filters设置为true(不写就是true),并且采用exclude-filter方式排出哪些注解标注的Bean不参与实例化:
执行测试程序:


12.5 负责注入的注解
@Component @Controller @Service @Repository 这四个注解是用来声明Bean的,声明后这些Bean将被实例化。接下来我们看一下,如何给Bean的属性赋值。给Bean属性赋值需要用到这些注解:
@Value
@Autowired
@Qualifier
@Resource
12.5.1 @Value
当属性的类型是简单类型时,可以使用@Value注解进行注入。
开启包扫描:
执行结果:


通过以上代码可以发现,我们并没有给属性提供setter方法,但仍然可以完成属性赋值。
如果提供setter方法,并且在setter方法上添加@Value注解,可以完成注入吗?尝试一下:
执行结果:


通过测试可以得知,@Value注解可以直接使用在属性上,也可以使用在setter方法上。都是可以的。都可以完成属性的赋值。
为了简化代码,以后我们一般不提供setter方法,直接在属性上使用@Value注解完成属性赋值。
出于好奇,我们再来测试一下,是否能够通过构造方法完成注入:
执行结果:


通过测试得知:@Value注解可以出现在属性上、setter方法上、以及构造方法的形参上。可见Spring给我们提供了多样化的注入。太灵活了。
12.5.2 @Autowired与@Qualifier
@Autowired注解可以用来注入非简单类型。被翻译为:自动连线的,或者自动装配。
单独使用@Autowired注解,默认根据类型装配。【默认是byType】
看一下它的源码:
源码中有两处需要注意:
第一处:该注解可以标注在哪里?
构造方法上
方法上
形参上
属性上
注解上
第二处:该注解有一个required属性,默认值是true,表示在注入的时候要求被注入的Bean必须是存在的,如果不存在则报错。如果required属性设置为false,表示注入的Bean存在或者不存在都没关系,存在的话就注入,不存在的话,也不报错。
我们先在属性上使用@Autowired注解:
执行结果:


以上构造方法和setter方法都没有提供,经过测试,仍然可以注入成功。
接下来,再来测试一下@Autowired注解出现在setter方法上:
执行结果:


我们再来看看能不能出现在构造方法上:
执行结果:


再来看看,这个注解能不能只标注在构造方法的形参上:
执行结果:


还有更劲爆的,当有参数的构造方法只有一个时,@Autowired注解可以省略。
执行结果:


当然,如果有多个构造方法,@Autowired肯定是不能省略的。
执行结果:


到此为止,我们已经清楚@Autowired注解可以出现在哪些位置了。
@Autowired注解默认是byType进行注入的,也就是说根据类型注入的,如果以上程序中,UserDao接口还有另外一个实现类,会出现问题吗?
当你写完这个新的实现类之后,此时IDEA工具已经提示错误信息了:


错误信息中说:不能装配,UserDao这个Bean的数量大于1.
怎么解决这个问题呢?当然要byName,根据名称进行装配了。
@Autowired注解和@Qualifier注解联合起来才可以根据名称进行装配,在@Qualifier注解中指定Bean名称。
执行结果:


总结:
@Autowired注解可以出现在:属性上、构造方法上、构造方法的参数上、setter方法上。
当带参数的构造方法只有一个,@Autowired注解可以省略。
@Autowired注解默认根据类型注入。如果要根据名称注入的话,需要配合@Qualifier注解一起使用。
12.5.3 @Resource
@Resource注解也可以完成非简单类型注入。那它和@Autowired注解有什么区别?
@Resource注解是JDK扩展包中的,也就是说属于JDK的一部分。所以该注解是标准注解,更加具有通用性。(JSR-250标准中制定的注解类型。JSR是Java规范提案。)
@Autowired注解是Spring框架自己的。
@Resource注解默认根据名称装配byName,未指定name时,使用属性名作为name。通过name找不到的话会自动启动通过类型byType装配。
@Autowired注解默认根据类型装配byType,如果想根据名称装配,需要配合@Qualifier注解一起用。
@Resource注解用在属性上、setter方法上。
@Autowired注解用在属性上、setter方法上、构造方法上、构造方法参数上。
@Resource注解属于JDK扩展包,所以不在JDK当中,需要额外引入以下依赖:【如果是JDK8的话不需要额外引入依赖。高于JDK11或低于JDK8需要引入以下依赖。】
一定要注意:如果你用Spring6,要知道Spring6不再支持JavaEE,它支持的是JakartaEE9。(Oracle把JavaEE贡献给Apache了,Apache把JavaEE的名字改成JakartaEE了,大家之前所接触的所有的  javax.*  包名统一修改为  jakarta.*包名了。)
@Resource注解的源码如下:


测试一下:
执行测试程序:


我们把UserDaoForOracle的名字xyz修改为userDao,让这个Bean的名字和UserService类中的UserDao属性名一致:
执行测试程序:


通过测试得知,当@Resource注解使用时没有指定name的时候,还是根据name进行查找,这个name是属性名。
接下来把UserService类中的属性名修改一下:
执行结果:


根据异常信息得知:显然当通过name找不到的时候,自然会启动byType进行注入。以上的错误是因为UserDao接口下有两个实现类导致的。所以根据类型注入就会报错。
我们再来看@Resource注解使用在setter方法上可以吗?
注意这个setter方法的方法名,setUserDao去掉set之后,将首字母变小写userDao,userDao就是name
执行结果:


当然,也可以指定name:
执行结果:


一句话总结@Resource注解:默认byName注入,没有指定name时把属性名当做name,根据name找不到时,才会byType注入。byType注入时,某种类型的Bean只能有一个。
12.6 全注解式开发
所谓的全注解开发就是不再使用spring配置文件了。写一个配置类来代替配置文件。
编写测试程序:不再new ClassPathXmlApplicationContext()对象了。
执行结果:



十三、JdbcTemplate
JdbcTemplate是Spring提供的一个JDBC模板类,是对JDBC的封装,简化JDBC代码。
当然,你也可以不用,可以让Spring集成其它的ORM框架,例如:MyBatis、Hibernate等。
接下来我们简单来学习一下,使用JdbcTemplate完成增删改查。
13.1 环境准备
数据库表:t_user


IDEA中新建模块:spring6-007-jdbc


引入相关依赖:
准备实体类:表t_user对应的实体类User。
编写Spring配置文件:
JdbcTemplate是Spring提供好的类,这类的完整类名是:org.springframework.jdbc.core.JdbcTemplate
我们怎么使用这个类呢?new对象就可以了。怎么new对象,Spring最在行了。直接将这个类配置到Spring配置文件中,纳入Bean管理即可。
我们来看一下这个JdbcTemplate源码:



可以看到JdbcTemplate中有一个DataSource属性,这个属性是数据源,我们都知道连接数据库需要Connection对象,而生成Connection对象是数据源负责的。所以我们需要给JdbcTemplate设置数据源属性。
所有的数据源都是要实现javax.sql.DataSource接口的。这个数据源可以自己写一个,也可以用写好的,比如:阿里巴巴的德鲁伊连接池,c3p0,dbcp等。我们这里自己先手写一个数据源。
写完数据源,我们需要把这个数据源传递给JdbcTemplate。因为JdbcTemplate中有一个DataSource属性:
到这里环境就准备好了。
13.2 新增
编写测试程序:
update方法有两个参数:
第一个参数:要执行的SQL语句。(SQL语句中可能会有占位符 ? )
第二个参数:可变长参数,参数的个数可以是0个,也可以是多个。一般是SQL语句中有几个问号,则对应几个参数。
13.3 修改
执行结果:


13.4 删除
执行结果:


13.5 查询一个对象
执行结果:


queryForObject方法三个参数:
第一个参数:sql语句
第二个参数:Bean属性值和数据库记录行的映射对象。在构造方法中指定映射的对象类型。
第三个参数:可变长参数,给sql语句的占位符问号传值。
13.6 查询多个对象
执行结果:


13.7 查询一个值
执行结果:


13.8 批量添加
执行结果:


13.9 批量修改
执行结果:


13.10 批量删除
执行结果:


13.11 使用回调函数
使用回调函数,可以参与的更加细节:

Java

复制代码


@Test

publicvoidtestCallback(){

// 获取JdbcTemplate对象

ApplicationContextapplicationContext=newClassPathXmlApplicationContext("spring.xml");

JdbcTemplatejdbcTemplate=applicationContext.getBean("jdbcTemplate",JdbcTemplate.class);

Stringsql="select id, real_name, age from t_user where id = ?";


Useruser=jdbcTemplate.execute(sql,newPreparedStatementCallback<User>(){

       @Override

publicUserdoInPreparedStatement(PreparedStatementps)throwsSQLException,DataAccessException{

Useruser=null;

ps.setInt(1,5);

ResultSetrs=ps.executeQuery();

if(rs.next()){

user=newUser();

user.setId(rs.getInt("id"));

user.setRealName(rs.getString("real_name"));

user.setAge(rs.getInt("age"));

}

returnuser;

}

});

System.out.println(user);

}

执行结果:


13.12 使用德鲁伊连接池
之前数据源是用我们自己写的。也可以使用别人写好的。例如比较牛的德鲁伊连接池。
第一步:引入德鲁伊连接池的依赖。(毕竟是别人写的)

德鲁伊依赖 pom.xml

XML

复制代码

<dependency>

<groupId>com.alibabagroupId>

<artifactId>druidartifactId>

<version>1.1.8version>

dependency>

第二步:将德鲁伊中的数据源配置到spring配置文件中。和配置我们自己写的一样。

spring.xml

XML

复制代码


<beansxmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


<beanid="druidDataSource"class="com.alibaba.druid.pool.DruidDataSource">

<propertyname="driverClassName"value="com.mysql.cj.jdbc.Driver"/>

<propertyname="url"value="jdbc:mysql://localhost:3306/spring6"/>

<propertyname="username"value="root"/>

<propertyname="password"value="root"/>

bean>


<beanid="jdbcTemplate"class="org.springframework.jdbc.core.JdbcTemplate">

<propertyname="dataSource"ref="druidDataSource"/>

bean>

beans>

测试结果:


相关文章
|
12天前
|
XML Java 数据格式
SpringBoot入门(8) - 开发中还有哪些常用注解
SpringBoot入门(8) - 开发中还有哪些常用注解
30 0
|
19天前
|
XML JSON Java
SpringBoot必须掌握的常用注解!
SpringBoot必须掌握的常用注解!
42 4
SpringBoot必须掌握的常用注解!
|
9天前
|
存储 运维 安全
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
21 2
|
21天前
|
存储 缓存 Java
Spring缓存注解【@Cacheable、@CachePut、@CacheEvict、@Caching、@CacheConfig】使用及注意事项
Spring缓存注解【@Cacheable、@CachePut、@CacheEvict、@Caching、@CacheConfig】使用及注意事项
67 2
|
20天前
|
JSON Java 数据库
SpringBoot项目使用AOP及自定义注解保存操作日志
SpringBoot项目使用AOP及自定义注解保存操作日志
34 1
|
14天前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
28 0
|
15天前
|
存储 安全 Java
springboot当中ConfigurationProperties注解作用跟数据库存入有啥区别
`@ConfigurationProperties`注解和数据库存储配置信息各有优劣,适用于不同的应用场景。`@ConfigurationProperties`提供了类型安全和模块化的配置管理方式,适合静态和简单配置。而数据库存储配置信息提供了动态更新和集中管理的能力,适合需要频繁变化和集中管理的配置需求。在实际项目中,可以根据具体需求选择合适的配置管理方式,或者结合使用这两种方式,实现灵活高效的配置管理。
12 0
|
6月前
|
Java API Spring
Spring容器如何使用一个注解来指定一个类型为配置类型
Spring容器如何使用一个注解来指定一个类型为配置类型
52 0
|
1月前
|
XML Java 数据格式
手动开发-简单的Spring基于注解配置的程序--源码解析
手动开发-简单的Spring基于注解配置的程序--源码解析
47 0
|
5月前
|
XML Java 数据格式
Spring5系列学习文章分享---第三篇(AOP概念+原理+动态代理+术语+Aspect+操作案例(注解与配置方式))
Spring5系列学习文章分享---第三篇(AOP概念+原理+动态代理+术语+Aspect+操作案例(注解与配置方式))
52 0
下一篇
无影云桌面