Spring框架学习(一)
Spring框架学习
Spring框架学习第一天 学习视频:【黑马程序员SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术】https://www.bilibili.com/video/BV1Fi4y1S7ix?p=27&vd_source=2884b80d333f3bfc8048b360e6195550
Spring框架
IoC(控制反转)
Dao
public class BookDaoImpl implements BookDao {
@Override
public void save() {
System.out.println("book dao save ");
}
}
public interface BookDao {
public void save();
}
Service
public class BookServiceImpl implements BookService {
private BookDao bookDao = new BookDaoImpl();
public void save(){
System.out.println("book service save");
bookDao.save();
}
}
public interface BookService {
public void save();
}
测试类
public class Main {
public static void main(String[] args) {
BookService bookService = new BookServiceImpl();
bookService.save();
}
}
可以看到我们最后在使用时是new service实现类然后完成工作,自己来管理操作bean
而IoC则是如下概念,将对象创建控制权转移给外部,也就是Spring提供的IoC容器

如何使用IoC容器
1.spring依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
2配置bean
创建applicationContext.xml
<bean id = "bookDao" class="com.kudo.dao.impl.BookDaoImpl"/>
3.通过IoC容器获取bean
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) context.getBean("bookDao");
bookDao.save();
DI(依赖注入)
依赖注入,可以看到业务层是使用到了数据层的类,在之前的代码我们是使用new bookDao来解决,在IoC容器中,我们可以通过DI注入来代替new,达到解耦合的效果,绑定两者间的依赖关系

删除new方法创建对象,并提供set方法使得获取dao类,配置applicationContext.xml。
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public void save(){
System.out.println("book service save");
bookDao.save();
}
public void setBookDao(BookDao bookDao){
this.bookDao = bookDao;
}
}
<bean id = "bookDao" class="com.kudo.dao.impl.BookDaoImpl"/>
<bean id = "bookService" class="com.kudo.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
</bean>

依赖注入的方式:
1.setter注入
- 引用类型:
也就是上面的提供set方法以及在xml配置中使用ref引用
要注入多个引用类型,设置set方法以及使用多个property标签即可
- 简单类型
public class BookDaoImpl implements BookDao, InitializingBean, DisposableBean {
private int conNum;
private String dbName;
public void setDbName(String dbName) {
this.dbName = dbName;
}
public void setConNum(int conNum) {
this.conNum = conNum;
}
public void save() {
System.out.println("book dao save "+ this.dbName +" " +this.conNum);
}
}
xml配置
<bean id = "bookDao" class="com.kudo.dao.impl.BookDaoImpl">
<property name="conNum" value="10"/>
<property name="dbName" value="mysql"/>
</bean>
2.构造器注入
- 引用类型
public class BookServiceImpl implements BookService{
private BookDao bookDao;
public BookServiceImpl(BookDao bookDao){
this.bookDao = new BookDaoImpl();
}
public void save(){
System.out.println("book service save");
bookDao.save();
}
}
xml配置,注意这里的bookDao是构造函数的形参,然后通过ref引用拿对象
<bean id = "bookService" name="service bookser" class="com.kudo.service.impl.BookServiceImpl" scope="prototype">
<constructor-arg name="bookDao" ref="bookDao"/>
</bean>
- 简单类型
public class BookServiceImpl implements BookService{
private int conNum;
private String dbName;
public BookServiceImpl(int conNum,String dbName) {
this.dbName = dbName;
this.conNum = conNum;
}
public void save(){
System.out.println("book service save"+" conNum="+conNum +" dbName="+dbName);
}
}
<bean id = "bookService" name="service bookser" class="com.kudo.service.impl.BookServiceImpl" scope="prototype">
<constructor-arg name="conNum" value="10"/>
<constructor-arg name="dbName" value="mysql"/>
</bean>
解决形参耦合
<bean id = "bookService" name="service bookser" class="com.kudo.service.impl.BookServiceImpl" scope="prototype">
<constructor-arg type="int" value="10"/>
<constructor-arg type="java.lang.String" value="mysql"/>
</bean>
如有多个同样类型参数还可使用index,参数位置
<bean id = "bookService" name="service bookser" class="com.kudo.service.impl.BookServiceImpl" scope="prototype">
<constructor-arg index="0" value="10"/>
<constructor-arg index="1" value="mysql"/>
</bean>
3.自动装配
- 引用类型
自动调用set方法或者构造器进行装配,但是要保证你装配的如BookDao是唯一类型
<bean id = "bookService" name="service bookser" class="com.kudo.service.impl.BookServiceImpl" autowire="byType">
无法对简单类型进行操作
4.集合注入
public class BookDaoImpl implements BookDao {
private int[] array;
private List<String> list;
private Set<Integer> set;
private Map<Integer,String> map;
public void setSet(Set<Integer> set) {
this.set = set;
}
public void setArray(int[] array) {
this.array = array;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMap(Map<Integer, String> map) {
this.map = map;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
private Properties properties;
public BookDaoImpl() {
System.out.println("bookDaoImpl 无参构造");
}
public void save() {
System.out.println("book dao save ");
System.out.println("遍历Array"+Arrays.toString(array));
System.out.println("遍历List"+list);
System.out.println("遍历Set"+set);
System.out.println("遍历Map"+map);
System.out.println("遍历Properties"+properties);
}
}
<bean id = "bookDao" class="com.kudo.dao.impl.BookDaoImpl">
<property name="array">
<array>
<value>100</value>
<value>200</value>
<value>300</value>
</array>
</property>
<property name="list">
<list>
<value>hello</value>
<value>wejsd</value>
<value>fhqwd</value>
</list>
</property>
<property name="set">
<set>
<value>1</value>
<value>2</value>
<value>3</value>
</set>
</property>
<property name="map">
<map>
<entry key="1" value="csdn"/>
<entry key="2" value="cnblog"/>
<entry key="3" value="xz"/>
</map>
</property>
<property name="properties">
<props>
<prop key="num">2</prop>
<prop key="city">xsd</prop>
<prop key="province">hd</prop>
</props>
</property>
</bean>
Bean的配置
name标签
bean的别名 通过name属性可以起多个别名,通过空格分开
<bean id = "bookService" name="service bookser" class="com.kudo.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
</bean>
可以通过Ioc取bean,也可以在依赖注入配置ref中使用
BookService bookService = (BookService) context.getBean("bookser");
<bean id = "bookDao" name="dao" class="com.kudo.dao.impl.BookDaoImpl"/>
<bean id = "bookService" name="service bookser" class="com.kudo.service.impl.BookServiceImpl">
<property name="bookDao" ref="dao"/>
</bean>
scope标签
单例模式:在spring中IoC 取bean默认是同一个对象(只创建一个),为了节省资源
通过scope可以改成多例模式
<bean id = "bookService" name="service bookser" class="com.kudo.service.impl.BookServiceImpl" scope="prototype">
<property name="bookDao" ref="dao"/>
</bean>

适合单例:
- 表现层对象
- 业务层对象
- 数据层对象
- 工具对象
不适合:封装实体的域或者对象
bean的实例化
同样的例子
说明Spring创建时是调用的无参构造
public class BookDaoImpl implements BookDao {
public BookDaoImpl() {
System.out.println("bookDaoImpl 无参构造");
}
public void save() {
System.out.println("book dao save ");
}
}
//会打印 bookDaoImpl 无参构造 且无论这个构造为私有还是公有
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) context.getBean("bookDao");
通过工厂创建bean(静态工厂) 可以达到一定的解耦,且可以在工厂中一些配置
不依赖的spring的做法:
public class BookDaoFactory {
public static BookDao getBookDao(){
return new BookDaoImpl();
}
}
Main:
BookDao bookDao1 = BookDaoFactory.getBookDao();
bookDao1.save();
使用spring操作:
<bean id = "bookDao" name="dao" class="com.kudo.dao.impl.BookDaoImpl"/>
更换为
<bean id = "bookDao" class="com.kudo.factory.BookDaoFactory" factory-method="getBookDao"/>
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) context.getBean("bookDao");
bookDao.save();
实例工厂初始化bean(不使用spring)
public class BookDaoFactory2 {
public BookDao getBookDao(){
return new BookDaoImpl();
}
}
BookDaoFactory2 bookDaoFactory2 = new BookDaoFactory2();
BookDao bookDao = bookDaoFactory2.getBookDao();
bookDao.save();
使用spring
配置:得先创建工厂对象 ,测试代码不变
<bean id = "bookDaoFactory2" class="com.kudo.factory.BookDaoFactory2"/>
<bean id = "bookDao" factory-bean="bookDaoFactory2" factory-method="getBookDao"/>
Spring提供了固定的实例工厂创建
实现FactoryBean接口,泛型中写要返回的对象类型
public class BookDaoFactoryBean implements FactoryBean<BookDao> {
@Override
public BookDao getObject() throws Exception {
return new BookDaoImpl();
}
@Override
public Class<?> getObjectType() {
return BookDao.class;
}
}
xml配置
<bean id = "bookDao" class="com.kudo.factory.BookDaoFactoryBean"/>
单例多例模式可以重写isSingleton切换
bean的生命周期
bean的初始化和销毁
public class BookDaoImpl implements BookDao {
public BookDaoImpl() {
System.out.println("bookDaoImpl 无参构造");
}
public void save() {
System.out.println("book dao save ");
}
//bean初始化对应的操作
public void init(){
System.out.println("bookDaoImpl init ");
}
//bean销毁前对应的操作
public void destroy(){
System.out.println("bookDaoImpl destroy");
}
}
<bean id = "bookDao" class="com.kudo.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy"/>

最后只打印了init,原因是结束时jvm直接over了,bean还没有来得及销毁
(ClassPathXmlApplicationContext)context.close,提前关闭容器即会出现销毁操作
或者context.registerShutdownHook();在关闭容器之前先销毁bean
同样spring提供了规范化的操作,实现两个接口
public class BookDaoImpl implements BookDao, InitializingBean, DisposableBean {
public BookDaoImpl() {
System.out.println("bookDaoImpl 无参构造");
}
public void save() {
System.out.println("book dao save ");
}
@Override
public void destroy() throws Exception {
System.out.println("bookDaoImpl destroy");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("bookDaoImpl afterPropertiesSet");
}
}
<bean id = "bookDao" class="com.kudo.dao.impl.BookDaoImpl"/>
第三方bean管理
例如:
druid依赖中的bean
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.18</version>
</dependency>
也是同样的配置手法,DruidDataSource中提供set方法
<bean id = "dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:// ..."/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
加载properties文件
如jdbc.properties
//jdbc的配置信息
jdbc.driver =
jdbc.url= .....
现在xml配置文件中开辟空间
原:
<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
">
开辟后:
<beans xmlns="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/beans/spring-context.xsd
">
然后通过context空间加载properties并使用
<context:property-placeholder location="jdbc.properties"/>
<bean id = "dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value=${jdcb.driver}/>
...
</bean>
${}还会调用系统属性,如${username}会加载计算机名

Spring 框架注解开发
注解定义bean以及配置类
通过注解定义bean
//可以不命名,在getBean(bookDao)保证只有唯一的bookDao类的bean
@Component("bookDao")
public class BookDaoImpl implements BookDao {
public BookDaoImpl() {
System.out.println("bookDaoImpl 无参构造");
}
public void save() {
System.out.println("book dao save ");
}
}
代替
<bean id = "bookDao" class="com.kudo.dao.impl.BookDaoImpl"/>
如何让spring扫描,在xml中配置扫描
<context:component-scan base-package="com.kudo.dao.impl"/>
@Service,@Repository,@Controller与@Component的作用完全一致,用来区分
@Service用于业务层
@Repository用于数据层
@Controller用于表现层
纯注解开发
使用类代替xml配置 @Configuration代替配置类中xml的原始定义,@ComponentScan("com.kudo")代表扫描bean,然后放入ioc容器,此为扫描com.kudo下的所有配置的bean
package com.kudo.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.kudo") //@ComponentScan({"com.kudo.dao","com.kudo.service"})扫描多个
public class SpringConfig {
}
此时如何获取容器,使用注解相关容器实现类 AnnotationConfigApplicationContext
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
注解下的bean相关
多例模式
@Scope
@Scope("prototype")
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
public BookDaoImpl() {
System.out.println("bookDaoImpl 无参构造");
}
public void save() {
System.out.println("book dao save ");
}
}
生命周期方法
@PostConstruct @PreDestroy
@Scope("prototype")
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
public BookDaoImpl() {
System.out.println("bookDaoImpl 无参构造");
}
public void save() {
System.out.println("book dao save ");
}
@PostConstruct
public void init(){
System.out.println("bookDao init ");
}
@PreDestroy
public void destroy(){
System.out.println("bookDao destroy");
}
}
注解下的依赖注入
@Autowired 通过暴力反射,所以可以不用写set方法,但是必须提供构造方法
@Autowired也可以放在任意位置
@Service("bookService")
public class BookServiceImpl implements BookService{
private BookDao bookDao;
@Autowired
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public BookServiceImpl() {
}
public void save(){
System.out.println("book service save");
}
}
@Service("bookService")
public class BookServiceImpl implements BookService{
@Autowired
private BookDao bookDao;
public BookServiceImpl() {
}
public void save(){
System.out.println("book service save");
}
}
如果有多个相同类型的bean
如BookDao1 ,BookDao2
通过@Qualifier指定名称
@Service("bookService")
public class BookServiceImpl implements BookService{
@Autowired
@Qualifier("bookDao2")
private BookDao bookDao;
public BookServiceImpl() {
}
public void save(){
System.out.println("book service save");
}
}
注入简单类型,@Value即可
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
@Value("zhangsan")
private String name;
public void save() {
System.out.println("book dao save "+name);
}
}
如何引用property配置文件中的数据
先加载PropertySource文件
@Configuration
@ComponentScan("com.kudo")
@PropertySource("jdbc.properties")
public class SpringConfig {
}
//然后直接使用${}引用即可
@Value({${jdbc.driver}})
private String name;
注解下第三方bean管理
在配置类中去创建Bean
容器获取bean时按类型即可
@Configuration
@ComponentScan("com.kudo")
@PropertySource("jdbc.properties")
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;
}
}
拆成多个配置文件
使用import导包
@Configuration
@ComponentScan("com.kudo")
@PropertySource("jdbc.properties")
@Import({JdbcConfig.class})
public class SpringConfig {
}
package com.kudo.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import javax.sql.DataSource;
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;
}
}

浙公网安备 33010602011771号