spring知识01

1、系统架构图

spring知识01_第1张图片

2、sping与springboot版本对应

springboot2.x对应spring5、springboot3.x对应spring6

3、Spring Ioc:将创建对象的控制权交给第三方容器

4、Spring DI(依赖注入):如何理解依赖注入,依赖就是conroller层依赖service,注入就是需要将service注入到controller中去

即 Ioc容器在运行期间,动态的将某种依赖关系自动注入

5、spring的优点就是维护性强,组件低耦合,耦合性低,复用性强(AOP)

6、Spring的原理图

​​​​​​​spring知识01_第2张图片

7、注册方式

(1)xml注册(少)

方式:写bean(声明要注册的对象)

bean属性

id属性 设置容器键的名称 id或name 不写的话就是class名+“#0”
class 设置类的全路径,底层通过反射创建对象
init-method 初始化方法
destroy-method 销毁方法
lazy-init 懒加载(默认是立即加载)
scope 作用域,表示单例(默认singleton)还是多例(prototype),request(Web应用中一次请求中有效),session,表示不同的session使用不同的对象
primary 如果一个接口在容器中存在多个实现类,设置为true表示优先选择该实例

注意:如果不是懒加载的话就表示对象在容器创建的时候就立即加载 ,懒加载是用的时候才加载

spring知识01_第3张图片




    
    

        (2)注解方式(多)

方式:开启全局扫描、写注解@Controller。。。

@Component代表=service controller,repository那些,是大的注解


    

 (3)JavaConfig(注册第三方的Bean:适用于第三方对象没办法用注解)

方式:开启全局扫描,新建config包,写xxxConfig,使用@Configuration注解(@Component也行),在方法上使用@Bean注解 (依赖注入)

@Configuration
public class DbUtilsConfig {
    // 默认情况Bean的Id是方法名称
//    Method  执行方法  返回值  获取方法名称  获取方法的参数
    @Bean
    public DbUtils dbUtils(DataSourceUtils dataSourceUtils) {
        DbUtils dbUtils = new DbUtils();
        dbUtils.setDataSourceUtils(dataSourceUtils);
        return dbUtils;
    }

    @Bean
    public DataSourceUtils dataSourceUtils() {
        DataSourceUtils dataSourceUtils = new DataSourceUtils();
        return dataSourceUtils;
    }

}

注意:全局对注解的扫描也是要开启的 ,必须使用public,返回值必须是注册的对象或者接口,在里面new的时候可以去new他的实现类      

8、当用到第三方框架的时候,使用注解注册就不方便,就要使用xml方式

9、一般两种方式可以混合用

 10、bean生命周期控制方法(连接池用的多)

(1)配置方法

spring知识01_第4张图片

注意:想要调用destory方法,就必须有一个关闭容器的方法 

(2)接口实现(了解)

spring知识01_第5张图片

    
    
        
    

11、lombok的使用

(1)@Data 

自动生成类的gettersetterequals()hashCode()toString()方法

(2)@NoArgsConstructor

自动生成一个无参构造函数

(3)@AllArgsConstructor

自动生成一个包含类中所有字段的构造函数

 12、constructor-arg子标签:通过构造方法(跟依赖注入的意思差不多,依赖注入就是写子属性那些什么的意思)

通过构造方法给对象的属性赋值

属性三种方式

(1)name 通过参数的名称

(2) index 通过参数数组的索引

(3)type 通过类型来赋值

(4)value设置基本数据类型的值

(5)ref设置引用类型的值 (指向容器中的某个对象)

spring知识01_第6张图片

13、property:通过属性的方式赋值(必须写setter方法(@Data))

属性

(1)name 属性的名称

(2)value设置基本数据类型的值

(3)ref设置引用类型的值(指向容器中的某个对象)

快捷方式:

 ​​​​​​​

导入p标签

14、依赖注入DI(Dependency Injection)(多)也有赋值的意思(可以混用)

在容器中建立bean与bean之间的依赖关系的过程,class里面写实现类全路径,可以用接口

spring知识01_第7张图片​​​​​​​

(1)xml方式(用lombok就可以不用写set和构造函数)

方式:写两个bean,然后其中一个里面写propertity/constructor-arg,还要有setter/构造方法

注意:两者必须在同一体系,不能一种是xml方式,另一种是直接new出来的spring知识01_第8张图片

        1)setter注入(自己用的多)

           1)简单类型 (用value)

spring知识01_第9张图片

                2)引用类型(用ref)

spring知识01_第10张图片

简写 

 spring知识01_第11张图片

         2)构造器注入

              1)简单类型

spring知识01_第12张图片

                2)引用类型

spring知识01_第13张图片

                       3)参数适配(额外的)

spring知识01_第14张图片

注意:



    
        
        
    


    
        
        
    v

(2)注解依赖注入(多)必须开启全局扫描

方式:开启全局扫描,写@Controller、@Service,然后在Controller里面直接调用@Autowired调用

​​​​​​​

@Autowired @Resource @Qualifier @Inject(基本不用)
spring提供的通过类型查找,如果存在则直接赋值  如果没有找到或者找到多个类型直接抛出异常

是jsr-250提供

   1. 默认情况通过名字查找容器的对象 ,如果通过名字没找到对象,就会通过类型查找    如果都没有直接抛出异常

   2. 如果给name属性赋值,只会通过name去查找对象,如果找不到直接抛出异常

   3. 如果name属性根type属性都赋值, 两者都必须同时匹配.否则直接抛出异常

一定要配合@Autowire注解一起使用,通过名字来查找容器中的对象   jsr-330提供

      

@Controller

public class UserController {

    @Autowired

    @Qualifier("userServiceImpl")

    private UserService userService;

(3)JavaConfig(注册第三方的Bean:适用于第三方对象没办法用注解)

方式:开启全局扫描,新建config包,写xxxConfig,使用@Configuration注解(@Component也行),在方法上使用@Bean注解​​​​​​​

@Configuration
public class DbUtilsConfig {
    // 默认情况Bean的Id是方法名称
//    Method  执行方法  返回值  获取方法名称  获取方法的参数
    @Bean
    public DbUtils dbUtils(DataSourceUtils dataSourceUtils) {
        DbUtils dbUtils = new DbUtils();
        dbUtils.setDataSourceUtils(dataSourceUtils);
        return dbUtils;
    }

    @Bean
    public DataSourceUtils dataSourceUtils() {
        DataSourceUtils dataSourceUtils = new DataSourceUtils();
        return dataSourceUtils;
    }

}

注意:必须使用public,返回值必须是注册的对象或者接口,在里面new的时候可以选择去new他的实现类, 

15、关于JavaConfig方式的Bean调用(依赖注入)

(1)直接调用:因为dataSourceUtils类在下面已经被注入进去了,所以上面直接声明一下就可以了 (只有一个就可以用)

@Configuration
public class DbUtilsConfig {
    // 默认情况Bean的Id是方法名称
//    Method  执行方法  返回值  获取方法名称  获取方法的参数
    @Bean
    public DbUtils dbUtils(DataSourceUtils dataSourceUtils) {
        DbUtils dbUtils = new DbUtils();
        dbUtils.setDataSourceUtils(dataSourceUtils);
        return dbUtils;
    }

    @Bean
    public DataSourceUtils dataSourceUtils() {
        DataSourceUtils dataSourceUtils = new DataSourceUtils();
        return dataSourceUtils;
    }

}

(2)声明为全局变量之后,利用注解注入后调用(多个)

spring知识01_第15张图片

16、依赖注入里面第一种方式xml注入都是属性注入,还有构造方法注入、setter方法注入

(1)构造方法注入:

        通过在类的构造方法中接收外部提供的依赖来完成注入的方式。在Spring框架中,可以通过在构造方法上添加@Autowired注解来实现自动注入

(2)setter方法注入:

        通过调用类的setter方法来注入依赖的方式。在Spring框架中,可以通过在setter方法上添加@Autowired注解来实现自动注入。

(3)构造器注入和属性注入都可能产生循环依赖问题

问题描述:循环依赖指的是两个或多个Bean之间互相持有对方,形成了一个闭环。这种情况会导致一个Bean依赖于另一个Bean,而后者又依赖于前者,形成一个无限循环

        1)在属性注入中,Spring首先创建bean的实例,然后通过setter方法注入依赖关系。所以属性注入一般不会产生循环依赖问题,但如果两个类通过@Autowired自动依赖注入对方,即类A包含一个类B的对象引用并需要自动注入,类B包含一个类A的对象引用也需要自动注入,那么就会产生循环依赖问题。

        2)构造器注入中,如果两个bean相互依赖,Spring无法同时创建它们,因为每个bean的创建都需要另一个bean作为参数。这种情况下,Spring无法解决循环依赖,会抛出一个BeanCurrentlyInCreationException异常。

        3)Setter注入,对于Setter注入,Spring会首先创建bean的实例,然后通过setter方法注入依赖关系。所以Setter注入不会产生循环依赖问题。

解决方案:

Spring 的三级缓存解决循环依赖

循环依赖 三级缓存 提前暴露

循环依赖是什么:A 依赖 B,B 依赖 A

1、A 创建过程中需要 B,于是先将 A 放到三级缓存,去实例化 B。

2、B 实例化的过程中发现需要 A,于是 B 先查一级缓存寻找 A,如果没有,再查二级缓存,如果还没有,再查三级缓存,找到了 A,然后把三级缓存里面的这个 A 放到二级缓存里面,并删除三级缓存里面的 A。

3、B 顺利初始化完毕,将自己放到一级缓存里面(此时 B 里面的 A 依然是创建中的状态)。然后回来接着创建 A,此时 B 已经创建结束,可以直接从一级缓存里面拿到 B,去完成 A 的创建,并将 A 放到一级缓存。

17、Spring解决单例的循环依赖问题的方式

(1)使用​​​​​​​@Lazy注解:

        当一个Bean被标记为@Lazy,Spring会延迟初始化这个Bean,直到它的一个属性被访问或者被注入到其他Bean中。
在循环依赖的情况下,使用@Lazy注解可以解决依赖初始化顺序的问题,因为依赖的Bean会在实际使用时才被加载。

(2)使用@Primary注解:

        当有多个同类型的Bean可供选择时,可以使用@Primary注解来指定首选的Bean。
在循环依赖的情况下,可以使用@Primary注解来指定先初始化的Bean,从而解决依赖问题。

(3)重构代码或调整Bean的依赖关系:

        有时候,循环依赖是由于代码结构或设计不当导致的。通过重构代码或调整Bean的依赖关系,可以消除循环依赖。
例如,将循环依赖的部分提取到一个单独的Bean中,或者调整Bean的初始化顺序。

(4)使用ApplicationContext的刷新机制:

        在某些情况下,可以使用ApplicationContext的刷新机制来手动控制Bean的初始化。
通过在应用上下文刷新之前创建并配置所有的Bean,可以避免循环依赖的问题。

(5)升级Spring版本:

在某些情况下,循环依赖问题可能是由于Spring版本中的Bug导致的。升级到最新的Spring版本可能会解决这个问题。

(6)使用第三方库或框架:

有些第三方库或框架提供了解决循环依赖问题的机制或工具,可以尝试使用这些库或框架来解决循环依赖问题。

18、map容器的键id或者name可以省略,一般是类名首字母小写,如果开头的字母连续个大写,则底层默认直接使用类名的

19、打开所在位置的文件路径

spring知识01_第16张图片

20、get请求没有请求体

21、请求头

spring知识01_第17张图片

22、实现原理

无反射,无框架、底层原理就是基于反射

23、IoC流程(本质是个map)

(1)导入spring依赖

    
      org.springframework
      spring-context
      5.3.31
    

(2)配置Bean

(3)获取ioc容器

        //获取ioc容器 ApplicationContext apx = new  ClassPathXmlApplicationContext("applicationContext.xml");

(4)获取bean

     //获取bean UserService userService = (UserService) apx.getBean("userService");

(5)执行方法

userService.save();

24、命名空间:用来限制标签内容

spring知识01_第18张图片

 25、查看关系图

spring知识01_第19张图片​​​​​​​

ClassPathXmlApplicationContext关系图 

spring知识01_第20张图片

26、控制反转IoC(Inversion of Control)

使用对象时,由主动的new对象转为外部提供对象,此过程中对这创建控制权由程序转移到外部

27、注解可以重命名,没写就是类名首字母小写,也可以直接类名.class去调用

@Service("ddd")
public class UserServiceImpl implements UserService {
}

28、IoC容器负责对象的创建、初始化等一系列操作,被创建或被管理的对象在IoC容器中叫Bean

29、name起别名,定义多个别名可以用,;空格分隔

name="dataSource,druidDataSource2"




    



        
    

30、Bean默认单例(singleton),可以通过scope设置

31、Bean用单例的原因

性能和资源优化、共享状态、简化配置、避免多个线程同时访问同一个对象的情况,从而避免了状态不一致的问题

32、实例化Bean的方式(配置Bean)

(1)通过构造方法

spring知识01_第21张图片

public class Test02 {
    public static void main(String[] args) {
        //获取ioc容器
        ApplicationContext apx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取bean
        UserDao userDao = (UserDao) apx.getBean("userDao");
       userDao.save();

注意:spring创建Bean的时候,调用的是无参的构造方法

(2)通过静态工厂方式

spring知识01_第22张图片

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        OrderDao orderDao = (OrderDao) ctx.getBean("orderDao");

        orderDao.save();

(3)通过实例工厂

spring知识01_第23张图片

(4)使用FactoryBean创建(重)

package com.qf.factory;

import com.qf.dao.UserDao;
import com.qf.dao.impl.UserDaoImpl;
import org.springframework.beans.factory.FactoryBean;

public class UserDaoFactoryBean implements FactoryBean {
    //代替原始实例工厂创建对象的方法
    @Override
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }

    //得到Bean类型
    @Override
    public Class getObjectType() {
        return UserDao.class;
    }

    //决定他是否是单例(默认单例)
    @Override
    public boolean isSingleton() {
        return false;
    }
}
  

33、SpringIoc的底层执行流程

spring知识01_第24张图片

package com.qf.controller;

import com.qf.service.UserService;
import com.qf.service.impl.UserServiceImpl;

import java.util.HashMap;
import java.util.Map;

public class UserController {
    private UserService userService = new UserServiceImpl();

    private Map ioc = new HashMap();

    public String login(){
        userService.toString();

        //通过反射获取userserviceimpl的class对象
        Class cls = Class.forName("com.qf.service.impl.UserServiceImpl");
        //实例化userService对象
        Object o = cls.newInstance();

        //获取类名(返回的是全类名)
        String name = cls.getName();
        //注入对象
        ioc.put("userServiceImpl",o);
        

        return "登录0";
    }
}

34、注解注册原理

                 通过spring配置文件 获取扫描的根路径

                 遍历根路劲下的所有.class结尾的文件

                通过文件全路径获取class对象

                通过class对象获取类的上的注入注解对象

                如果对象不为空通过反射创建对象注册到容器中

注意:class.getAnnotation获取该class对象的注解

package com.qf;

import com.qf.controller.UserController;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

public class App {

    public static void main(String[] args) {
         Map ioc = new HashMap();

        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-ioc.xml");

        //通过类名获取class对象
        Class cla = UserController.class;

        //获取类上的注解
        Component annotation = cla.getAnnotation(Component.class);
        if (annotation !=null){
            //实例化对象
            UserController o = cla.newInstance();
            //put进去
            ioc.put("UserController",o);
        }

    }
}

35、注解方式没写名字的话,默认类名首字母小写

 36、依赖注入方式选择

37、依赖自动装配(byType多)。

这里

spring知识01_第25张图片

spring知识01_第26张图片

根据type的时候,bookdao的id都可以省略,因为它是根据类型来的,name就不行

name是对应这个名

spring知识01_第27张图片

38、依赖自动装配特征

spring知识01_第28张图片

39、value单属性可不写

40、注入集合对象

spring知识01_第29张图片




    

    
        

            100
            200
            300

        
    
    
        

            你好
            不错
            学习
        
    
    
        
            10
            20
            30
        
    
    
        
            
            
            
        
    
    
        
            china
            henan
            kaifeng
        
    


    


    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//       ctx.registerShutdownHook();
        UserDao userDao = (UserDao) ctx.getBean("userDao");
        userDao.save();

41、controller类似于servlet层

42、在接口没有实现的时候

spring知识01_第30张图片

写上


就可以在以接口接收的时候去调用实现类的方法

    public static void main(String[] args) {

        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao) ctx.getBean("userDao");
        userDao.save();

43、关闭容器的方法

 ctx.registerShutdownHook(); 注册关闭钩子
ctx.close(); 直接不保存关闭

44、这样写即使调用dao也会执行service

   
    

        
    

45、生命周期

spring知识01_第31张图片

spring知识01_第32张图片

46、调用service的save(自定义)方法的时候

会先调用dao的init方法

然后是service里面的set方法

service里的init方法

service的save

dao的save

service destroy
dao destory...

package com.qf.dao.impl;

import com.qf.dao.UserDao;
import org.springframework.stereotype.Repository;

@Repository
public class UserDaoImpl implements UserDao {

//    public UserDaoImpl() {
//        System.out.println("book dao constructor is running...");
//    }

    //表示bean初始化对应的操作
    public void init(){
        System.out.println("Userdao init...");
    }

    public void save(){
        System.out.println("user dao save...");
    }


    //表示bean销毁前对应的操作
    public void destory(){
        System.out.println("userdao destory...");
    }


}
package com.qf.service.impl;

import com.qf.dao.OrderDao;
import com.qf.dao.UserDao;
import com.qf.service.UserService;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;

//@Service
public class UserServiceImpl implements UserService, InitializingBean, DisposableBean {
    private UserDao userDao;
    private OrderDao orderDao;

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("service init");
    }

    public void save(){
        System.out.println("user service save...");
        userDao.save();
    }

    public void setUserDao(UserDao userDao) {
        System.out.println("set userdao.......");
        this.userDao = userDao;
    }


    @Override
    public void destroy() throws Exception {
        System.out.println("service destroy");
    }


}
    
    
        
    


46、数据源对象管理

spring知识01_第33张图片

47、加载properties文件

spring知识01_第34张图片

48、创建容器

spring知识01_第35张图片

49、获取bean

spring知识01_第36张图片

 50、容器类层次结构图

51、BeanFactory初始化(了解)

​​​​​​​spring知识01_第37张图片

52、容器相关

spring知识01_第38张图片

53、bean相关

spring知识01_第39张图片

54、圣旨谢升值,54依赖注入相关

spring知识01_第40张图片

55、注解开发定义bean

spring知识01_第41张图片

spring知识01_第42张图片

56、纯注解配置类开发Configuration

spring知识01_第43张图片

57、调用接口和调实现类都得到同样的东西

        当你调用ctx.getBean(BookDao.class)时,Spring会尝试找到一个实现了BookDao接口的bean。然后当你调用ctx.getBean(BookDaoImpl.class)时,Spring会找到一个名为BookDaoImpl的bean(可能是通过名称匹配)。

//这

58、注解在用完之后设置close就可以显示出destory方法

spring知识01_第44张图片

59、使用@Scope("singleton")定义作用范围)

  1. singleton:这是默认的生命周期。注解的实例在整个应用上下文中只有一个,所有地方共享这个实例。
  2. prototype:每次从上下文中请求这个bean时,都会创建一个新的实例。
  3. request:在Web应用中,每个HTTP请求都会有一个新的实例。
  4. session:在Web应用中,每个HTTP会话都会有一个新的实例。

60、使用@PostConstruct、@PreDestroy定义生命周期

package com.qf.dao.impl;

import com.qf.dao.BookDao;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Repository
@Scope("singleton")
public class BookDaoImpl implements BookDao {
    @Override
    public void save() {
        System.out.println("book dao save...");
    }

    @PostConstruct
    public void init(){
        System.out.println("init...");
    }

    @PreDestroy
    public void destory(){
        System.out.println("destory...");
    }

}

61、注解那里要写名字,不写的话默认是首字母小写的类名

62、使用@Autowried注解开启自动装配(按类型)

package com.qf.service.impl;

import com.qf.dao.BookDao;
import com.qf.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class BookServiceImpl implements BookService {
    @Autowired
    @Qualifier("bookDao2")
    private BookDao bookDao;
    
    @Override
    public void save() {
        System.out.println("book service save...");
        bookDao.save();
    }
}

63、使用了@Autowried还需要使用

        @Autowired注解用于自动装配bean,而标签用于指定Spring扫描的包路径,以便自动发现并注册bean

        即使你使用了@Autowired注解,你仍然需要使用标签来指定Spring扫描的包路径。因为的作用是告诉Spring去哪些包下寻找需要被Spring管理的bean,并且注册这些bean到Spring容器中

        所以,@Autowired是相互补充的,前者用于自动装配,后者用于指定需要被扫描的包路径。两者一起使用,才能实现Spring的自动装配功能

        当Spring容器启动时,它会扫描指定的包路径下的类,并注册带有@Component@Service@Repository@Controller等注解的类为bean。然后,在需要使用这些bean的地方,你可以使用@Autowired注解来自动装配它们

64、使用@Qualifier注解开启指定名称装配bean的话要搭配AutoWired使用 (相当于@Resource)

spring知识01_第45张图片

65、使用value实现简单类型的注入

spring知识01_第46张图片

66、使用@PropertySource注解加载properties文件(注解)

spring知识01_第47张图片

注意:@PropertySource("jdbc.properties")这样也行 

52、注解写了别名的话就是指定的,没有的话就是类名首字母小写,

67、类和接口用的是同一个Bean

BookDao bookDao1 = ctx.getBean(BookDao.class);

BookDaoImpl book11 = ctx.getBean(BookDaoImpl.class);

是同一个东西(除非设置scope)

68、第三方管理Bean(JavaConfig配置方式)

spring知识01_第48张图片

优化:将独立的配置类加入核心配置

(1)导入式

spring知识01_第49张图片

(2)扫描式

spring知识01_第50张图片

69、第三方Bean依赖注入

(1)简单类型依赖注入

spring知识01_第51张图片

(2)引用依赖注入

spring知识01_第52张图片

70、写的时候可以(“”)写,也可以直接类名.class去写

71、@Configuration和@ComponentScan("com.qf")用法

        @Configuration注解用于声明一个类作为配置类,该类包含一个或多个@Bean方法,这些方法用于创建并返回一个或多个Spring容器管理的bean。这些bean将自动注册到Spring应用程序上下文中,并可通过其他bean进行注入。

        @ComponentScan注解用于告诉Spring自动扫描指定包(或多个包)下的类,并将它们作为组件自动注册到Spring应用程序上下文中。这使得您无需手动声明每个bean,而是可以让Spring自动发现和注册符合条件的组件。

        通常情况下,您可以将@Configuration@ComponentScan一起使用,以便在配置类中声明组件并提供自动扫描功能

72、XMl配置对比注解配置

​​​​​​​spring知识01_第53张图片

73、@Autowired和@Resource依赖注入

(1)@Autowired  是spring提供的通过类型查找,如果存在则直接赋值  如果没有找到或者找到多个类型直接抛出异常

(2)@Resource    是jsr-250提供

(3)区别

   1. 默认情况@Resource通过名字查找容器的对象 ,如果通过名字没找到对象,就会通过类型查找    如果都没有直接抛出异常

   2. 如果给name属性赋值,只会通过name去查找对象,如果找不到直接抛出异常

   3. 如果name属性根type属性都赋值, 两者都必须同时匹配.否则直接抛出异常

74、请求头是键值对形式

你可能感兴趣的:(spring)