[Java]Spring-Day 2
[Java]Spring-Day2
学习使用工具
黑马2023新版Java视频教程 https://www.bilibili.com/video/BV1Fv4y1q7ZH?p=8&vd_source=03da0cdb826d78c565cd22a83928f4c2
Java程序员进阶之路 https://tobebetterjavaer.com/overview/java-can-do-what.html
黑马程序员SSM框架教程 https://www.bilibili.com/video/BV1Fi4y1S7ix?p=2&vd_source=03da0cdb826d78c565cd22a83928f4c2
一、数据源对象管理流程(第三方资源配置管理)
-
将相关工具先加入pom.xml
-
在bean配置文件(applicationContext.xml)中引入bean。由于是第三方库,要先查看源代码中有没有提供构造方法或setter方法,以决定用什么方式进行bean的参数注入。
二、加载properties文件
一些数据并不适合直接写在配置文件中(例如用户名和密码),需要写在properties文件中进行导入。
-
在applicationContext.xml中先引入外部properties文件
-
开启context命名空间
<?xml version="1. 0" encoding="UTF-8"?> <beans xm1ns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema -instance" xmlns: context= "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 http://www.springframework.org/schema/context/spring -context.xsd"> </beans>
-
使用context空间加载properties文件,location可以加载多个配置文件,以逗号分割,或以
classpath:*.properties
加载当前类下所有配置文件。classpath*:*.properties
可以加载所有jar包下的配置文件。<context:properties-placeholder location="jdbc.properties"></context>
-
将对应的value处改成属性占位符${},读取properties文件中的属性
-
三、容器补充
-
创建容器
类路径下的XML配置文件:
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
文件系统下的XML配置文件,双引号内要使用决定路径。
ApplicationContext ctx = new FileSystemXmlApplicationContext("applicationContext.xml");
-
获取bean
按名称获取
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
按名称获取,并解决强制类型转换问题
BookDao bookDao = ctx.getBean("bookDao",BookDao.class);
按类型获取,必须要确保IOC容器中该类型对应的bean对象只能有一个。
BookDao bookDao = ctx.getBean(BookDao.class);
四、IOC/DI注解开发
要想真正简化开发,就需要用到Spring的注解开发,Spring对注解支持的版本历程:
- 2.0版开始支持注解
- 2.5版注解功能趋于完善
- 3.0版支持纯注解开发
注解开发定义bean用的是2.5版提供的注解,纯注解开发用的是3.0版提供的注解。
-
注解开发定义Bean
-
删除原XML配置
将配置文件中的
<bean>
标签删除掉
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
-
Dao上添加注解
在BookDaoImpl类上添加
@Component
注解@Component("bookDao") public class BookDaoImpl implements BookDao { public void save() { System.out.println("book dao save ..." ); } }
注意:@Component注解不可以添加在接口上,因为接口是无法创建对象的。@Component注解如果不起名称,会有一个默认值就是
当前类名首字母小写
,所以也可以按照名称获取。对于@Component注解,还衍生出了其他三个注解
@Controller
、@Service
、@Repository
。这三个注解和@Component注解的作用是一样的,方便我们后期在编写类的时候能很好的区分出这个类是属于表现层
、业务层
还是数据层
的类。 -
步骤3:配置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" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <context:component-scan base-package="com.itheima"/> </beans>
说明:
component-scan
- component:组件,Spring将管理的bean视作自己的一个组件
- scan:扫描
base-package指定Spring框架扫描的包路径,它会扫描指定包及其子包中的所有类上的注解。
- 包路径越多[如:com.itheima.dao.impl],扫描的范围越小速度越快
- 包路径越少[如:com.itheima],扫描的范围越大速度越慢
- 一般扫描到项目的组织名称即Maven的groupId下[如:com.itheima]即可。
-
-
纯注解开发
上面已经可以使用注解来配置bean,但是依然有用到配置文件,在配置文件中对包进行了扫描,Spring在3.0版已经支持纯注解开发。
实现思路为:将配置文件applicationContext.xml删除掉,使用类来替换。
-
创建配置类
创建一个配置类
SpringConfig
-
标识该类为配置类:在配置类上添加
@Configuration
注解,将其标识为一个配置类,替换applicationContext.xml
-
用注解替换包扫描配置:在配置类上添加包扫描注解
@ComponentScan
替换<context:component-scan base-package=""/>
。@Configuration @ComponentScan("com.itheima") public class SpringConfig { }
@ComponentScan注解用于设定扫描路径,此注解只能添加一次,多个数据使用数组格式。
@ComponentScan({com.itheima.service","com.itheima.dao"})
-
创建运行类并执行,这里要将接口替换为纯注解开发使用的接口
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
-
-
注解开发bean作用范围
默认情况下bean是单例,要想将BookDaoImpl变成非单例,只需要在其类上添加
@scope
注解。@Repository //@Scope设置bean的作用范围 @Scope("prototype") public class BookDaoImpl implements BookDao { public void save() { System.out.println("book dao save ..."); } }
-
注解开发bean的生命周期
@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 ..."); } }
在BookDaoImpl中添加两个方法,
init
和destroy
,方法名可以任意,@PostConstruct和
@PreDestroy`注解分别标识初始化方法和销毁方法。@PostConstruct和@PreDestroy注解如果找不到,需要导入下面的jar包:<dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>1.3.2</version> </dependency>
-
注解开发依赖注入
Spring为了使用注解简化开发,并没有提供
构造函数注入
、setter注入
对应的注解,只提供了自动装配的注解实现。@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方法删除掉
。@Autowired是按照类型注入,那么对应BookDao接口如果有多个实现类,就会报错。可以通过给实现类起不同的名称来使自动装配成功。 -
注解开发按照名称注入
当根据类型在容器中找到多个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一起使用。
-
简单数据类型注入
@Repository("bookDao") public class BookDaoImpl implements BookDao { @Value("itheima") private String name; public void save() { System.out.println("book dao save ..." + name); } }
使用
@Value
注解,将值写入注解的参数中就行了。注意数据格式要匹配,如将"abc"注入给int值,这样程序就会报错。实际上跟直接赋值是一个效果,还没有直接赋值简单。
-
注解读取properties配置文件
已有的
jdbc.properties
配置文件,内容为name=itheima888
-
使用注解加载properties配置文件,在配置类上添加@PropertySource注解
@Configuration @ComponentScan("com.itheima") @PropertySource("jdbc.properties") public class SpringConfig { }
-
使用
@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
前面定义bean的时候都是在自己开发的类上面写个注解就完成了,但如果是第三方的类,这些类都是在jar包中,我们没有办法在类上面添加注解。这种方式不能在原始代码上面书写注解,一样能定义bean,这就用到了一个全新的注解@Bean。
-
导入对应jar包
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency>
-
在配置类中添加一个方法,该方法的返回值就是要创建的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; } }
-
在方法上添加
@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; } }
-
从IOC容器中获取对象即可
如果把所有的第三方bean都配置到Spring的配置类SpringConfig
中,虽然可以,但是不利于代码阅读和分类管理。对于数据源的bean,我们可以新建一个JdbcConfig
配置类,并把数据源配置到该类下。
令这个配置类能被Spring配置类加载到,并在IOC容器中创建DataSource对象的方法:
-
使用包扫描引入。在Spring的配置类上添加包扫描,在JdbcConfig上添加配置注解。
@Configuration @ComponentScan("com.itheima.config") public class SpringConfig { }
@Configuration 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; } }
-
使用
@Import
引入。不需要为JdbcConfig添加配置注解,只需在Spring配置类中引入:@Configuration //@ComponentScan("com.itheima.config") @Import({JdbcConfig.class}) public class SpringConfig { }
- 扫描注解可以移除
- @Import参数需要的是一个数组,可以引入多个配置类。
- @Import注解在配置类中只能写一次。
六、IOC/DI注解开发实现为第三方bean注入资源
-
简单数据类型
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; } }
-
类中提供四个属性
public class JdbcConfig { private String driver; private String url; private String userName; private String password; @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; } }
-
使用
@Value
注解引入值public class JdbcConfig { @Value("com.mysql.jdbc.Driver") private String driver; @Value("jdbc:mysql://localhost:3306/spring_db") private String url; @Value("root") private String userName; @Value("password") private String password; @Bean public DataSource dataSource(){ DruidDataSource ds = new DruidDataSource(); ds.setDriverClassName(driver); ds.setUrl(url); ds.setUsername(userName); ds.setPassword(password); return ds; } }
代码中关于数据库的四要素不应该写死在代码中,应该是从properties配置文件中读取。具体方法为:
- resources目录下添加jdbc.properties
- 配置文件中提供四个键值对分别是数据库的四要素
- 使用@PropertySource加载jdbc.properties配置文件
- 修改@Value注解属性的值,将其修改为
${key}
,key就是键值对中的键的值
-
-
引用数据类型
假设在构建DataSource对象的时候,需要用到BookDao对象,该如何把BookDao对象注入进方法内让其使用呢?
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; } }
-
在SpringConfig中扫描BookDao
扫描的目的是让Spring能管理到BookDao,也就是说要让IOC容器中有一个bookDao对象
@Configuration @ComponentScan("com.itheima.dao") @Import({JdbcConfig.class}) public class SpringConfig { }
-
在JdbcConfig类的方法上添加参数,引用类型注入只需要为bean定义方法设置形参即可,容器会根据类型自动装配对象。
@Bean public DataSource dataSource(BookDao bookDao){ System.out.println(bookDao); DruidDataSource ds = new DruidDataSource(); ds.setDriverClassName(driver); ds.setUrl(url); ds.setUsername(userName); ds.setPassword(password); return ds; }
-