<?xml version="1.0" encoding="UTF-8"?>
<context:property-placeholder location=“jdbc.properties”/>
▶ 注意事项
▷ 问题一 : 键值对的key为
username
引发的问题1.在properties中配置键值对的时候,如果key设置为
username
username=root666
2.在applicationContext.xml注入该属性
<?xml version="1.0" encoding="UTF-8"?>
<context:property-placeholder location=“jdbc.properties”/>
3.运行后,在控制台打印的却不是
root666
,而是自己电脑的用户名。出现问题的原因是<context:property-placeholder/>
标签会加载系统的环境变量,而且环境变量的值会被优先加载。运行下面的代码查看系统的环境变量:
public static void main(String[] args) throws Exception{
Map<String, String> env = System.getenv();
System.out.println(env);
}
解决方案
<context:property-placeholder location=“jdbc.properties”
system-properties-mode=“NEVER”/>
system-properties-mode: 设置为NEVER,表示不加载系统属性,就可以解决上述问题。
还有一个解决方案就是避免使用
username
作为属性的key
。▷ 问题二 : 当有多个properties配置文件需要被加载,该如何配置?
1.调整下配置文件的内容,在resources下添加
jdbc.properties
,jdbc2.properties
,内容如下:jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
jdbc.username=root
jdbc.password=root
jdbc2.properties
username=root666
2.修改applicationContext.xml
<context:property-placeholder location=“jdbc.properties,jdbc2.properties” system-properties-mode=“NEVER”/>
● 方式一 : 可以实现,如果配置文件多的话,每个都需要配置
<context:property-placeholder location=“*.properties” system-properties-mode=“NEVER”/>
● 方式二 :
\*.properties
代表所有以properties结尾的文件都会被加载,可以解决方式一的问题,但是不标准
<context:property-placeholder location=“classpath:*.properties” system-properties-mode=“NEVER”/>
● 方式三 : 标准的写法,
classpath:
代表的是从根路径下开始查找,但是只能查询当前项目的根路径
<context:property-placeholder location=“classpath*😗.properties” system-properties-mode=“NEVER”/>
● 方式四 : 不仅可以加载当前项目还可以加载当前项目所依赖的所有项目的根路径下的properties配置文件
▶ 小结
● 开启
context
命名空间:● 加载properties配置文件:
<context:property-placeholder location=“” system-properties-mode=“NEVER”/>
● 在applicationContext.xml引入properties配置文件中的值:
${key}
3、核心容器
▶ 容器的创建方式
▷ 类路径下的XML配置文件:直接加载类路径下的文件
ApplicationContext ctx =
new ClassPathXmlApplicationContext(“applicationContext.xml”);
▷ 文件系统下的XML配置文件:需要写完整的系统路径
ApplicationContext ctx =
new FileSystemXmlApplicationContext("
D:\workspace\spring\spring_10_container\
src\main\resources\applicationContext.xml");
▶ bean 获取的三种方式
▷ 方式一 :这种方式存在的问题是每次获取的时候都需要进行类型转换
BookDao bookDao = (BookDao) ctx.getBean(“bookDao”);
▷ 方式二:这种方式可以解决类型强转问题,但是参数又多加了一个。
BookDao bookDao = ctx.getBean(“bookDao”,BookDao.class);
▷ 方式三 : 这种方式就类似依赖注入中的按类型注入。必须要确保IOC容器中该类型对应的bean对象只能有一个。
BookDao bookDao = ctx.getBean(BookDao.class);
▶ 容器类层次结构
(1)在IDEA中双击
shift
,输入BeanFactory(2)点击进入BeanFactory类,ctrl+h,就能查看到如下结构的层次关系
▶ BeanFactory的使用
▷ 使用BeanFactory来创建IOC容器的具体实现方式为:
public class AppForBeanFactory {
public static void main(String[] args) {
Resource resources = new ClassPathResource(“applicationContext.xml”);
BeanFactory bf = new XmlBeanFactory(resources);
BookDao bookDao = bf.getBean(BookDao.class);
bookDao.save();
}
}
▷ 对比
● BeanFactory是延迟加载,只有在获取bean对象的时候才会去创建
● ApplicationContext是立即加载,容器加载的时候就会创建bean对象
● ApplicationContext要想成为延迟加载,只需要按照如下方式进行配置:(加上 lazy-init)
▶ 总结
▷ 容器相关
● BeanFactory是IoC容器的顶层接口,初始化BeanFactory对象时,加载的bean延迟加载
● ApplicationContext接口是Spring容器的核心接口,初始化时bean立即加载
● ApplicationContext接口提供基础的bean操作相关方法,通过其他接口扩展其功能
● ApplicationContext接口常用初始化类
○ ClassPathXmlApplicationContext(常用)
○ FileSystemXmlApplicationContext▷ bean相关
▷ 依赖注入相关
二、注解开发
1、注解开发定义bean
▶ 实现步骤
▷ 步骤1 : 删除原XML配置
将配置文件中的
<bean>
标签删除掉
▷ 步骤2 : Dao上添加注解
在BookDaoImpl类上添加
@Component
注解
@Component(“bookDao”)
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println(“book dao save …” );
}
}
● 注意 : @Component注解不可以添加在接口上,因为接口是无法创建对象的。
● XML与注解配置的对应关系:
▷ 步骤3 : 配置Spring的注解包扫描
为了让Spring框架能够扫描到写在类上的注解,需要在配置文件上进行包扫描
<?xml version="1.0" encoding="UTF-8"?><context:component-scan base-package=“com.itheima”/>
● 注意:
1、component-scan:
○ component : 组件,Spring将管理的bean视作自己的一个组件
○ scan:扫描2、base-package指定Spring框架扫描的包路径,它会扫描指定包及其子包中的所有类上的注解。
○ 包路径越多[如:com.itheima.dao.impl],扫描的范围越小速度越快
○ 包路径越少[如:com.itheima],扫描的范围越大速度越慢
○ 一般扫描到项目的组织名称即Maven的groupId下[如:com.itheima]即可。▷ 步骤4 : Service上添加注解
在BookServiceImpl类上也添加
@Component
交给Spring框架管理
@Component
public class BookServiceImpl implements BookService {
}
▷ 步骤5 : 运行程序
在App类中,从IOC容器中获取BookServiceImpl对应的bean对象,打印
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(“applicationContext.xml”);
//按名称
BookDao bookDao = (BookDao) ctx.getBean(“bookDao”);
System.out.println(bookDao);
//按类型获取bean
BookService bookService = ctx.getBean(BookService.class);
System.out.println(bookService);
}
}
说明 :
● BookServiceImpl类没有起名称,所以在App中是按照类型来获取bean对象
● @Component注解如果不起名称,会有一个默认值就是
当前类名首字母小写
,所以也可以按照名称获取,如:
BookService bookService = (BookService)ctx.getBean(“bookServiceImpl”);
System.out.println(bookService);
● 对于@Component注解,还衍生出了其他三个注解
@Controller
、@Service
、@Repository
通过查看源码会发现:(这三个注解和@Component注解的作用是一样的,为什么要衍生出这三个呢?为了方便我们后期在编写类的时候能很好的区分出这个类是属于
表现层
、业务层
还是数据层
的类。)● @Component
2、纯注解开发模式
▶ 实现方式
首先将配置文件applicationContext.xml删除掉,使用类来替换。
▷ 步骤1 : 创建配置类
创建一个配置类
SpringConfig
public class SpringConfig {
}
▷ 步骤2 : 标识该类为配置类
在配置类上添加
@Configuration
注解,将其标识为一个配置类,替applicationContext.xml
@Configuration
public class SpringConfig {
}
▷ 步骤3 : 用注解替换包扫描配置
在配置类上添加包扫描注解
@ComponentScan
替换<context:component-scan base-package=""/>
@Configuration
@ComponentScan(“com.itheima”)
public class SpringConfig {
}
▷ 步骤4 : 创建运行类并执行
创建一个新的运行类
AppForAnnotation
public class AppForAnnotation {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);BookDao bookDao = (BookDao) ctx.getBean(“bookDao”);
System.out.println(bookDao);BookService bookService = ctx.getBean(BookService.class);
System.out.println(bookService);
}
}
运行AppForAnnotation,可以看到两个对象依然被获取成功。
▶ 小总结
● Java类替换Spring核心配置文件
● @Configuration注解用于设定当前类为配置类
● @ComponentScan注解用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式
@ComponentScan({com.itheima.service",“com.itheima.dao”})
● 读取Spring核心配置文件初始化容器对象切换为读取Java配置类初始化容器对象
//加载配置文件初始化容器
ApplicationContext ctx = new ClassPathXmlApplicationContext(“applicationContext.xml”);//加载配置类初始化容器
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
● @Configuration
● @ComponentScan
3、注解开发bean作用范围与生命周期管理
▶ @Scope 注解
默认情况下bean是单例,要想变成非单例,只需要在其类上添加
@scope
注解,列如:
@Repository
//@Scope设置bean的作用范围
@Scope(“prototype”)
public class BookDaoImpl implements BookDao {public void save() {
System.out.println(“book dao save …”);
}
}
▶ Bean的生命周期
● @PostConstruct
● @PreDestroy
● 注意 : @PostConstruct和@PreDestroy注解如果找不到,需要导入下面的jar包。找不到的原因是,从JDK9以后jdk中的javax.annotation包被移除了,这两个注解刚好就在这个包中。
javax.annotation javax.annotation-api 1.3.2
例如:
@Repository
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println(“book dao save …”);
}
@PostConstruct //在构造方法之后执行,替换 init-method
public void init() {
System.out.println(“init …”);
}
@PreDestroy //在销毁方法之前执行,替换 destroy-method
public void destroy() {
System.out.println(“destroy …”);
}
}
要想看到两个方法执行,需要注意的是
destroy
只有在容器关闭的时候,才会执行。▶ 小结
4、注解开发依赖注入
● @Autowired
▶ 添加依赖
pom.xml 添加Spring的依赖
org.springframework spring-context 5.2.10.RELEASE
▶ 注解实现按照类型注入
▷ (1) 在BookServiceImpl类的bookDao属性上添加
@Autowired
注解
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookDao bookDao;
// public void setBookDao(BookDao bookDao) {
// this.bookDao = bookDao;
// }
public void save() {
System.out.println(“book service save …”);
bookDao.save();
}
}
注意:
● @Autowired可以写在属性上,也可也写在setter方法上,最简单的处理方式是
写在属性上并将setter方法删除掉
● 为什么setter方法可以删除呢?
○ 自动装配基于反射设计创建对象并通过暴力反射为私有属性进行设值
○ 普通反射只能获取public修饰的内容
○ 暴力反射除了获取public修饰的内容还可以获取private修改的内容
○ 所以此处无需提供setter方法▷ (2)@Autowired是按照类型注入,那么对应BookDao接口如果有多个实现类,比如添加BookDaoImpl2
@Repository
public class BookDaoImpl2 implements BookDao {
public void save() {
System.out.println(“book dao save …2”);
}
}
这个时候再次运行App,就会报错,此时,按照类型注入就无法区分到底注入哪个对象,解决方案:
按照名称注入
。▶ 问题
先给两个Dao类分别起个名称
@Repository(“bookDao”)
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println(“book dao save …” );
}
}
@Repository(“bookDao2”)
public class BookDaoImpl2 implements BookDao {
public void save() {
System.out.println(“book dao save …2” );
}
}
此时就可以注入成功,但是得思考个问题:
● @Autowired是按照类型注入的,给BookDao的两个实现起了名称,它还是有两个bean对象,为什么不报错? @Autowired默认按照类型自动装配,如果IOC容器中同类的Bean找到多个,就按照变量名和Bean的名称匹配。因为变量名叫
bookDao
而容器中也有一个booDao
,所以可以成功注入。● 分析下面这种情况是否能完成注入呢?
不行,因为按照类型会找到多个bean对象,此时会按照
bookDao
名称去找,因为IOC容器只有名称叫bookDao1
和bookDao2
,会找不到,会报NoUniqueBeanDefinitionException
异常。▶ 注解实现按照名称注入
● @Qualifier
当根据类型在容器中找到多个bean,注入参数的属性名又和容器中bean的名称不一致,这个时候该如何解决,就需要使用到
@Qualifier
来指定注入哪个名称的bean对象。
@Service
public class BookServiceImpl implements BookService {
@Autowired
@Qualifier(“bookDao1”)
private BookDao bookDao;
public void save() {
System.out.println(“book service save …”);
bookDao.save();
}
}
注意:@Qualifier注解后的值就是需要注入的bean的名称。@Qualifier不能独立使用,必须和@Autowired一起使用。
▶ 简单数据类型注入
● @Value
简单类型注入的是基本数据类型或者字符串类型,下面在
BookDaoImpl
类中添加一个name
属性,用其进行简单类型注入。数据类型换了,对应的注解也要跟着换,这次使用@Value
注解,将值写入注解的参数中就行了
@Repository(“bookDao”)
public class BookDaoImpl implements BookDao {
@Value(“itheima”)
private String name;
public void save() {
System.out.println(“book dao save …” + name);
}
}
注意数据格式要匹配,如将"abc"注入给int值,这样程序就会报错。
▶ 注解读取properties配置文件
● @PropertySource
▷ 步骤1:resource下准备properties文件
name=itheima888
▷ 步骤2 : 使用注解加载properties配置文件
在配置类上添加
@PropertySource
注解
@Configuration
@ComponentScan(“com.itheima”)
@PropertySource(“jdbc.properties”)
public class SpringConfig {
}
▷ 步骤3:使用@Value读取配置文件中的内容
@Repository(“bookDao”)
public class BookDaoImpl implements BookDao {
@Value(“${name}”)
private String name;
public void save() {
System.out.println(“book dao save …” + name);
}
}
注意:
● 如果读取的properties配置文件有多个,可以使用
@PropertySource
的属性来指定多个
@PropertySource({“jdbc.properties”,“xxx.properties”})
●
@PropertySource
注解属性中不支持使用通配符\*
,运行会报错
@PropertySource({“*.properties”})
●
@PropertySource
注解属性中可以把classpath:
加上,代表从当前项目的根路径找文件
@PropertySource({“classpath:jdbc.properties”})
三、IOC/DI注解开发管理第三方bean
● pom.xml添加Spring的依赖
org.springframework spring-context 5.2.10.RELEASE
1、注解开发管理第三方bean
● @Bean
▶ 实现步骤
▷ 步骤1 : 导入对应的jar包
com.alibaba druid 1.1.16
▷ 步骤2 : 在配置类中添加一个方法
注意该方法的返回值就是要创建的Bean对象类型
@Configuration
public class SpringConfig {
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(“com.mysql.jdbc.Driver”);
ds.setUrl(“jdbc:mysql://localhost:3306/spring_db”);
ds.setUsername(“root”);
ds.setPassword(“root”);
return ds;
}
}
▷ 步骤3 : 在方法上添加
@Bean
注解@Bean注解的作用是将方法的返回值制作为Spring管理的一个bean对象
@Configuration
public class SpringConfig {
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(“com.mysql.jdbc.Driver”);
ds.setUrl(“jdbc:mysql://localhost:3306/spring_db”);
ds.setUsername(“root”);
ds.setPassword(“root”);
return ds;
}
}
注意 : 不能使用
DataSource ds = new DruidDataSource()
,因为DataSource接口中没有对应的setter方法来设置属性。▷ 步骤4 : 从IOC容器中获取对象并打印
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
DataSource dataSource = ctx.getBean(DataSource.class);
System.out.println(dataSource);
}
}
▶ 引入外部配置类
● @Import
对于数据源的bean,我们新建一个
JdbcConfig
配置类,并把数据源配置到该类下。
public class JdbcConfig {
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(“com.mysql.jdbc.Driver”);
ds.setUrl(“jdbc:mysql://localhost:3306/spring_db”);
ds.setUsername(“root”);
ds.setPassword(“root”);
return ds;
}
}
这个配置类如何能被Spring配置类加载到,并创建DataSource对象在IOC容器中?
针对这个问题,有两个解决方案:
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Go语言工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Go语言全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Golang知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Go)
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
ClassName(“com.mysql.jdbc.Driver”);
ds.setUrl(“jdbc:mysql://localhost:3306/spring_db”);
ds.setUsername(“root”);
ds.setPassword(“root”);
return ds;
}
}
这个配置类如何能被Spring配置类加载到,并创建DataSource对象在IOC容器中?
针对这个问题,有两个解决方案:
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Go语言工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Go语言全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-N2SzNLrD-1712878023465)]
[外链图片转存中…(img-auu8wd3T-1712878023466)]
[外链图片转存中…(img-jDBce1C7-1712878023467)]
[外链图片转存中…(img-sHU7GYK5-1712878023467)]
[外链图片转存中…(img-phuyRN12-1712878023468)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Golang知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Go)
[外链图片转存中…(img-WAUXMK3y-1712878023468)]
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!