https://img2024.cnblogs.com/blog/3305226/202503/3305226-20250331155133325-143341361.jpg

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容器

image-20250606170136420

如何使用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,达到解耦合的效果,绑定两者间的依赖关系

image-20250606171221796

删除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>

image-20250606174440767

依赖注入的方式:

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>

image-20250606175257116

适合单例:

  • 表现层对象
  • 业务层对象
  • 数据层对象
  • 工具对象

不适合:封装实体的域或者对象

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"/>

image-20250606184133893

最后只打印了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}会加载计算机名

image-20250606202710737

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;
    }
}
posted @ 2025-06-07 17:42  kudo4869  阅读(42)  评论(0)    收藏  举报