Spring框架学习笔记

学习视频:6001 Spring概述_哔哩哔哩_bilibili~7012 Bean的生命周期_哔哩哔哩_bilibili

目录

1.Spring概述

1.1框架的核心技术

 1.2Spring在表现层、业务逻辑层和持久层的作用

2.框架优点

a.非侵入式设计

b.降低耦合性

c.支持AOP编程

d.支持声明式事务

e.方便程序的测试

f.方便集成框架

g.降低Java EE API的使用难度

3.Spring的体系结构

结构图

a.核心容器模块(Core Container)

b.数据访问及集成模块(Data Access/Integration)

c.Web模块

d.其他模块

4.Spring5的新特性

a.更新JDK基线

b.修订核心框架

c.更新核心容器

d.支持响应式编程

e.支持函数式Web框架

f.支持Kotlin

g.提升测试功能

2.Spring的目录结构

3.Spring的入门程序

5.控制反转与依赖注入

控制反转

依赖注入

依赖注入的实现方式

 构造方法注入

        属性setter方法注入 

依赖注入的应用

6.Spring中的Bean的管理

        BeanFactory接口

ApplicationContext接口

Bean的配置

静态工厂实例化

实例工厂实例化

7.Bean的作用域

8.Bean的装配方式

基于注解的装配

自动装配

Bean的生命周期


1.Spring概述

1.1框架的核心技术

         Spring是由Rod Johnson组织和开发的一个分层的Java SE/EE一站式(full-stack)轻量级开源框架。它最为核心的理念是IoC(控制反转)和AOP(面向切面编程),其中,IoC是Spring的基础,它支撑着Spring对JavaBean的管理功能;AOP是Spring 的重要特性,AOP是通过预编译方式和运行期间动态代理实现程序功能,也就是说可以在不修改源代码的情况下,给程序统一添加功能。


 1.2Spring在表现层、业务逻辑层和持久层的作用

包括但不限于:

  1. 在表现层它提供了Spring MVC框架,并且Spring还可以与Struts框架整合。
  2. 在业务逻辑层可以管理事务、记录日志等。
  3. 在持久层可以整合MyBatis、Hibernate、JdbcTemplate等技术。

2.框架优点

a.非侵入式设计

        Spring是一种非侵入式(non-invasive)框架,所谓非侵入式是指Spring框架的API不会在业务逻辑上出现,也就是说业务逻辑应该是纯净的,不能出现与业务逻辑无关的代码。由于业务逻辑中没有Spring的API,所以业务逻辑代码也可以从Spring框架快速地移植到其他框架。

b.降低耦合性

         Spring就是一个大工厂,可以将所有对象的创建和依赖关系的维护工作都交给Spring容器管理,大大降低了组件之间的耦合性

c.支持AOP编程

        Spring提供了对AOP的支持,AOP可以将一些通用的任务进行集中处理,如安全、事务和日志等,以减少通过传统OOP方法带来的代码冗余和繁杂

d.支持声明式事务

        在Spring中,可以直接通过Spring配置文件管理数据库事务,省去了手动编程的繁琐,提高了开发效率

e.方便程序的测试

        Spring提供了对Junit的支持,开发人员可以通过Junit进行单元测试。

f.方便集成框架

        Spring提供了一个广阔的基础平台,其内部提供了对各种框架的直接支持,如Struts、Hibernate、MyBatis、Quartz等,这些优秀框架可以与Spring无缝集成。

g.降低Java EE API的使用难度

 Spring对Java EE开发中的一些API(如JDBC、JavaMail等)都进行了封装,大大降低了这些API的使用难度。(之前12345才能完成,现在123即可)


3.Spring的体系结构

结构图


a.核心容器模块(Core Container)

         核心容器模块在Spring的功能体系中起着支撑性作用,是其他模块的基石。核心容器层主要由Beans模块、Core模块、Contex模块和SpEL模块组成。

核心容器模块各模块组成

  1. Beans模块。它提供了BeanFactory类,是工厂模式的经典实现,Beans模块的主要作用是创建和管理Bean对象。        
  2. Core模块。它提供了Spring框架的基本组成部分,包括IoC和DI功能。        
  3. Context模块。它构建于Beans模块和Core模块的基础之上,它可以通过ApplicationContext接口提供上下文信息。        
  4. SpEL模块。它是Spring 3.0后新增的模块,提供了对SpEL表达式语言(Spring Expression Language)的支持,SpEL表达式语言是一个在程序运行时支持操作对象图的表达式语言。

b.数据访问及集成模块(Data Access/Integration)

   数据访问及集成模块用于访问和操作数据库中的数据,它主要包含JDBC模块、ORM模块、OXM模块、JMS模块和Transactions模块。

  1.  JDBC模块。它提供了一个JDBC的抽象层,消除了冗长的JDBC编码并能够解析数据库供应商特有的错误代码。        
  2. ORM模块。它为主流的对象关系映射API提供了集成层,用于集成主流的对象关系映射框架。      
  3.  OXM模块。它提供了对XML映射的抽象层的支持,如JAXB、Castor等。    
  4.  JMS模块。它主要用于传递消息,包含消息的生产和消费。自4.1版本后,JMS模块支持与Spring-message模块的集成。        
  5. Transactions模块。它的主要功能是事务管理。

c.Web模块

         Web模块的实现基于APPlicationContext基础之上,它提供了Web应用的各种工具类,包括了Web模块、Servlet模块、WebSocket模块和Portlet模块。

Web模块各模块组成

  1.  Web模块。它提供了针对Web开发的集成特性,如大部分文件上传功能等。此外,Web模块还包含一个HTTP客户端和Spring远程处理支持的Web相关部分。        
  2. Servlet模块。它提供了Spring的模型、视图、控制器以及Web应用程序的REST Web服务实现。        
  3. WebSocket模块。它是Spring 4.0以后新增的模块,它提供了WebSocket 和SockJS的实现,以及对STOMP的支持。         
  4. Portlet模块。它类似Servlet模块的功能,提供了Portlet环境下的MVC实现。

d.其他模块

   Spring框架的其他模块还有AOP模块、Aspects模块、Instrumentation模块以及Test模块。

其他模块各模块组成

  1.  AOP模块。它提供了对面向切面编程的支持,程序可以定义方法拦截器和切入点,将代码按照功能进行分离,以降低程序的耦合性。        
  2. Aspects模块。它提供了与AspectJ集成的支持。        
  3. Instrumentation模块。它提供了对类工具的支持,并且实现了类加载器,该模块可以在特定的应用服务器中使用。        
  4. Messaging模块。它是Spring 4.0以后新增的模块,它提供了对消息传递体系结构和协议的支持。        
  5. Test模块。它提供了对程序单元测试和集成测试的支持。

4.Spring5的新特性

a.更新JDK基线

         因为Spring 5代码库运行于JDK 8之上,所以Spring 5对JDK的最低要求是JDK 8,这可以促进Spring的使用者积极运用Java 8新特性。


b.修订核心框架

  1. 基于JDK 8的反射增强,通过Spring 5提供的方法可以更加高效的对类或类的参数进行访问。        
  2. 核心的Spring接口提供了基于JDK 8的默认方法构建的选择性声明。      
  3.  用@Nullable和@NotNull注解来表明可为空的参数以及返回值,可以在编译时处理空值而不是在运行时抛出NullPointerExceptions异常。

c.更新核心容器

    Spring 5支持候选组件索引作为类路径扫描的替代方案。从索引读取实体类,会使加载组件索引开销更低,因此,Spring程序的启动时间将会缩减


d.支持响应式编程

        响应式编程是另外一种编程风格,它专注于构建对事件做出响应的应用程序。Spring 5包含响应流和Reactor(ReactiveStream的Java实现),响应流和Reactor支撑了Spring自身的功能及相关API。


e.支持函数式Web框架

        Spring 5提供了一个函数式Web框架。该框架使用函数式编程风格来定义端点,它引入了两个基本组件: HandlerFunction和RouterFunctionHandlerFunction 表示处理接收到的请求并生成响应函数;RouterFunction替代了@RequestMapping注解,用于将接收到的请求转发到处理函数。


f.支持Kotlin

 Spring 5提供了对Kotlin语言的支持。Kotlin是一种支持函数式编程风格的面向对象语言,它运行在JVM之上,可以让代码更具有表现力、简洁性和可读性。有了对Kotlin的支持,开发人员可以进行深度的函数式Spring编程,这拓宽了Spring的应用领域。


g.提升测试功能

        Spring 5完全支持Junit 5 Jupiter,因此可以使用Junit 5编写测试代码。除此之外,Spring 5还提供了在Spring TestContext Framework中进行并行测试的扩展。针对响应式编程模型,Spring 5引入了支持Spring webFlux的WebTestClient集成测试。


2.Spring的目录结构

        目录结构下文件夹的介绍

        docs文件夹:该文件夹下存放Spring的相关文档,包括开发指南、API参考文档。                 libs文件夹:该文件夹下存放开发所需的jar包和源码。整个Spring框架由21个模块组成,libs目录下Spring为每个模块都提供了三个压缩包,因此,libs文件夹下一共有63个jar包。这63个jar包分为三类。      

        schema文件夹:该文件夹下存放Spring各种配置文件的XML Schema文档。


3.Spring的入门程序

public class HelloSpring {
    private String userName;

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public void show()
    {
        System.out.println(userName+",你好,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">
    <bean id="helloSpring" class="com.it.HelloSpring">
        <property name="userName" value="张三"></property>
    </bean>


</beans>
public class HelloSpringTest {

    public static void main(String[] args) {
        //1.获取spring容器
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");

        //2.从spring容器获取对象
        HelloSpring helloSpring=(HelloSpring)applicationContext.getBean("helloSpring");

        //3.调用对象方法
        helloSpring.show();

    }
}


5.控制反转与依赖注入

控制反转

传统面向对象程序设计原则

          控制反转(Inversion of Control,缩写为IoC)是面向对象编程中的一个设计原则,用来降低程序代码之间的耦合度。在传统面向对象编程中,获取对象的方式是用new关键字主动创建一个对象,也就是说应用程序掌握着对象的控制权。传统面向对象程序设计原则如图。


IoC设计原则

          IoC控制反转机制指的是对象由Ioc容器统一管理,当程序需要使用对象时,可以直接从IoC容器中获取。这样对象的控制权就从应用程序转移到了IoC容器。IoC设计原则如图,它是借助于IoC容器实现具有依赖关系对象之间的解耦,各个对象类封装之后,通过IoC容器来关联这些对象类。


依赖注入

        依赖注入(Dependency Inject,缩写DI)就是由IoC容器在运行期间动态地将某种依赖资源注入对象之中。例如,将对象B注入(赋值)给对象A的成员变量。依赖注入的基本思想是:明确地定义组件接口,独立开发各个组件,然后根据组件的依赖关系组装运行。

依赖注入和控制反转的比较

          依赖注入(DI)和控制反转(IoC)是从不同角度来描述了同一件事情。依赖注入是从应用程序的角度描述,即应用程序依赖IoC容器创建并注入它所需要的外部资源;而控制反转是从IoC容器的角度描述,即IoC容器控制应用程序,由IoC容器反向地向应用程序注入应用程序所需要的外部资源。这里所说的外部资源可以是外部实例对象,也可以是外部文件对象等。


依赖注入的实现方式

          依赖注入的作用就是在使用Spring框架创建对象时,动态的将其所依赖的对象注入到Bean组件中。依赖注入通常有两种实现方式,一种是构造方法注入,另一种是属性setter方法注入。这两种实现方式具体介绍如下。

 构造方法注入

          构造方法注入是指Spring容器调用构造方法注入被依赖的实例,构造方法可以是有参的或者是无参的。Spring在读取配置信息后,会通过反射方式调用实例的构造方法,如果是有参构造方法,可以在构造方法中传入所需的参数值,最后创建类对象。

代码实现

public class User1 {
    private  int id;
    private String username;
    private String password;

    @Override
    public String toString() {
        return "User1{" +
                "id=" + id +
                ", name='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    public User1(String username, String password, int id) {
        this.username = username;
        this.password = password;
        this.id = id;
    }
}
  <bean id="user1" class="com.it.User1">
        <constructor-arg name="id" value="1"></constructor-arg>
        <constructor-arg name="username" value="张三"></constructor-arg>
        <constructor-arg name="password" value="123"></constructor-arg>
    </bean>

public class User1Test {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        User1 user1 = (User1) context.getBean("user1");
        System.out.println(user1);

    }
}


        属性setter方法注入 

        属性setter方法注入是Spring最主流的注入方法,这种注入方法简单、直观,它是在被注入的类中声明一个setter方法,通过setter方法的参数注入对应的值。

public class User2 {
    private  int id;
    private String username;
    private String password;
    private User1 user1;

    public void setUser1(User1 user1) {
        this.user1 = user1;
    }

    public void setIdd(int id) {
        this.id = id;
    }


    public void setUsername(String username) {
        this.username = username;
    }


    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User2{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", user1=" + user1 +
                '}';
    }
}
   <bean id="user2" class="com.it.User2">
    <property name="idd" value="2"></property>
    <property name="username" value="李四"></property>
        <property name="password" value="1234"></property>
        <property name="user1" ref="user1"></property>
    </bean>
public class User2Test {
    public static void main(String[] args) {
        ApplicationContext  applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        User2 user2 = (User2)applicationContext.getBean("user2");
        System.out.println(user2);


    }
}

注意:这里name="idd"这个是去掉set的命名,以及搞引用的话比如user1对象得用ref


依赖注入的应用
public interface UserDao {
    public boolean login(String username, String password);

}
public class UserDaoImpl implements UserDao {
    @Override
    public boolean login(String username, String password) {
        if ("张三".equals(username) && "123".equals(password)) {
            return true;
        }else
        {
            return false;
        }


    }
}
public interface UserService {
    public boolean login(String username, String password);


}
public class UserServiceImpl implements UserService {
    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public boolean login(String username, String password) {
        return userDao.login(username, password);

    }
}
    <bean id="userDao" class="com.it.dao.impl.UserDaoImpl"></bean>
    <bean id="userService" class="com.it.service.impl.UserServiceImpl">
        <property name="UserDao" ref="userDao">
        </property>
    </bean>
public class LoginTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService =(UserService) context.getBean("userService");
        boolean result = userService.login("张三", "123");
        if(result)
        {
            System.out.println("登录成功");
        }else
        {
            System.out.println("登录失败");
        }


    }
}


6.Spring中的Bean的管理

        BeanFactory接口

BeanFactory接口实例的语法格式

BeanFactory beanFactory=new XmlBeanFactory     (new FileSystemResource(”D:/bean.xml”));


public interface OrderService {


}
import com.it.service.OrderService;

public class OrderServiceImpl implements OrderService {
    public OrderServiceImpl()
    {
        System.out.println("构造方法调用了");
    }

}
    <bean id="orderService" class="com.it.service.impl.OrderServiceImpl"></bean>



public class App {
    public static void main(String[] args) {
        /*     BeanFactory默认是第一次获取对象时,创建对象
        */
        BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource("D:\\03HANJIA\\Days007\\src\\main\\resources\\applicationContext.xml"));
        OrderServiceImpl orderService=(OrderServiceImpl)beanFactory.getBean("orderService");
        System.out.println(orderService);
       OrderService orderService1 =beanFactory.getBean(OrderService.class);
        System.out.println(orderService1);


    }
}


ApplicationContext接口

        ApplicationContext接口建立在BeanFactory接口(第一次获取对象时创建)的基础之上,它丰富了BeanFactory接口的特性,例如,添加了对国际化、资源访问、事件传播等方面的支持。         ApplicationContext接口可以为单例的Bean实行预初始化,并根据<property>元素执行setter方法,单例的Bean可以直接使用,提升了程序获取Bean实例的性能。

ApplicationContext接口的常用实现类

是BeanFactory的子接口,在容器初始化时,就创建bean了


Bean的配置

Spring容器所支持的配置文件格式

         Spring容器支持XMLProperties两种格式的配置文件,在实际开发中,最常用的是XML格式的配置文件。XML是标准的数据传输和存储格式,方便查看和操作数据。在Spring中,XML配置文件的根元素是<beans>,<beans>元素包含<bean>子元素,每个<bean>子元素可以定义一个Bean,通过<bean>元素将Bean注册到Spring容器中。

<bean>元素的常用属性

<bean>元素的常用子元素

普通的Bean通常只需定义id(或者name)和class两个属性


静态工厂实例化

public class Bean1 {
    public Bean1()
    {
        System.out.println("bean1的构造方法");
    }
}

public class MyBean1Factory {
    public static Bean1 createBean1() {
        System.out.println("工厂的静态方法");
       return new Bean1();

    }
}
 <bean id="bean1" class="com.it.factory.MyBean1Factory" factory-method="createBean1"></bean>
public class Bean1Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Bean1 bean1 = (Bean1) context.getBean("bean1");
        System.out.println(bean1);
    }
}

如果是接口只能用这个 (因为接口没构造方法)


实例工厂实例化

public class Bean2 {
    public Bean2() {
        System.out.println("这是Bean2");
    }
}
import com.it.beans.Bean2;

public class MyBean2Factory {
    public MyBean2Factory()
    {
        System.out.println("实例化工厂的构造方法");
    }
    public Bean2 createBean()
    {
        return new Bean2();
    }


}

        <bean id="bean2Factory"  class="com.it.factory.MyBean2Factory"></bean>
        <bean id="bean2" factory-bean="bean2Factory" factory-method="createBean"></bean>
public class Bean2Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Bean2 bean2 = (Bean2) context.getBean("bean2");
        System.out.println(bean2);


    }
}


优化版

public class Bean3 {
    public Bean3() {
        System.out.println("这是bean3");
    }
}
public class MyBean3Factory implements FactoryBean<Bean3> {


    @Override
    public Bean3 getObject() throws Exception {
        System.out.println("FactoryBean接口的getObject方法");
        return new Bean3();
    }

    @Override
    public Class<?> getObjectType() {
        return Bean3.class;
    }
}
 <bean id="bean3" class="com.it.factory.MyBean3Factory"></bean>
public class Bean3Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Object bean3= context.getBean("bean3");
        System.out.println(bean3);


    }
}


7.Bean的作用域

Spring支持的5种作用域

   <bean id="bean1" class="com.it.beans.Bean1" scope="singleton"></bean>

public class SingletonTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Object bean1=context.getBean("bean1");
        Object bean2=context.getBean("bean1");

        System.out.println(bean1==bean2);
    }
}

scope改为prototype结果会是false,因为会获取一个新的对象


8.Bean的装配方式

两种基于XML的装配方式

         在基于XML的装配就是读取XML配置文件中的信息完成依赖注入,Spring容器提供了两种基于XML的装配方式,属性setter方法注入和构造方法注入。下面分别对这两种装配方式进行介绍。

a.属性setter方法注入

        属性setter方法注入要求一个Bean必须满足以下两点要求。        

        (1)Bean类必须提供一个默认的无参构造方法。    

        (2)Bean类必须为需要注入的属性提供对应的setter方法。

b.构造方法注入

          使用构造方法注入时,在配置文件里,需要使用<bean>元素的子元素<constructor-arg>来定义构造方法的参数,例如,可以使用其value属性(或子元素)来设置该参数的值。


基于注解的装配

XML注解装配的比较

        在Spring中,使用XML配置文件可以实现Bean的装配工作,但在实际开发中如果Bean的数量较多,会导致XML配置文件过于臃肿,给后期维护和升级带来一定的困难。为解决此问题,Spring提供了注解,通过注解也可以实现Bean的装配。

Spring的常用注解


基于注解的装配

自动扫描:

 <context:component-scan base-package="com.it"></context:component-scan>
public interface UserDao {
    public void save();

}
@Repository("userDao")
public class UserDaoImpl implements UserDao {


    @Override
    public void save() {
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
            User user = (User) context.getBean("user");
        System.out.println(user);
        System.out.println("调用了userDao的save方法");

    }
}
public interface UserService {
  public void save();

}
@Service("userService")
public class UserServiceImpl implements UserService {
    @Resource(name="userDao")
    private UserDao userDao;

    @Override
    public void save() {
        userDao.save();
        System.out.println("调用了userService的save方法");


    }
}
@Controller("userController")
public class UserController {
    @Resource(name="userService")
    private UserService userService;
    public void save()
    {
            userService.save();
        System.out.println("调用了userController的save方法");
    }


}
public class AnnotationTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
      UserController userController= (UserController) context.getBean("userController");
            userController.save();


    }

}


自动装配

如何实现自动装配

          Spring的<bean>元素中包含一个autowire属性,可以通过设置autowire属性的值实现Bean的自动装配。

autowire属性的值

public class User1 {
    private  int id;
    private String username;
    private String password;
    private Bean1 bean1;

    public User1() {

    }

    @Override
    public String toString() {
        return "User1{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", bean1=" + bean1 +
                '}';
    }

    public Bean1 getBean1() {
        return bean1;
    }

    public void setBean1(Bean1 bean1) {
        this.bean1 = bean1;
    }

    public User1(int id, String username, String password, Bean1 bean1) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.bean1 = bean1;
    }
}
<bean id="bean1" class="com.it.beans.Bean1" ></bean>
    <bean id="user1" class="com.it.beans.User1" autowire="byType">
    </bean>

public class XMLDITest {
    public static void main(String[] args) {
        ApplicationContext  context=new ClassPathXmlApplicationContext("applicationContext.xml");
        User1 user1=(User1)context.getBean("user1");
        System.out.println(user1.getBean1());
    }
}


使用Autowired注解

测试

 如果userDao创建了多个,可以用Qualifier配合使用


Bean的生命周期

Bean在不同作用域内的生命周期

        Bean的生命周期是指Bean实例被创建初始化销毁的过程。在Bean的两种作用域singleton和prototype中,Spring容器对Bean的生命周期的管理是不同的。在singleton作用域中,Spring容器可以管理Bean的生命周期,控制着Bean的创建、初始化和销毁。在prototype作用域中, Spring容器只负责创建Bean实例,不会管理其生命周期。

Bean生命周期的两个时间节点

        在Bean的生命周期中,有两个时间节点尤为重要,这两个时间节点分别是Bean实例初始化后和Bean实例销毁前,在这两个时间节点通常需要完成一些指定操作。因此,常常需要对这两个节点进行监控。

监控时间节点的方式

监控两个节点的方式有两种,一种是使用XML配置文件,一种是使用注解


@Component("student")
public class Student {
        @Value("1")
    private  int   id;
      @PostConstruct
    public  void init()
      {
          System.out.println("初始时要调用的方法");
      }
    @PreDestroy
    public void destroy()
    {
        System.out.println("销毁时要调用的方法:destroy");
    }


}
public class AnnotationTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
      Student student =(Student) context.getBean("student");
        System.out.println(student);
        AbstractApplicationContext ac=(AbstractApplicationContext) context;
        ac.registerShutdownHook();


    }

}

  • 22
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小吴有想法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值