Spring框架详解(IOC容器-上)

IOC( Inversion of Control,控制反转)和DI(dependency injection)是Spring框架的核心特性,也是Spring框架的基础。

Spring框架作为一个IOC容器,负责加载、创建和管理Spring Bean。

接下来介绍基于Spring传统的配置方式——xml配置文件来配置Spring Bean。

控制反转

IOC-控制反转指的是:我们程序员把创建、管理对象的工作交给了Spring框架,而不是自己通过new关键字调用构造方法创建。

依赖注入

在一个Spring Bean中,可以通过DI特性将另外一个Bean作为成员变量(依赖)添加到当前Bean中。

Spring默认不会处理Bean中的成员变量,需要通过一定的配置,让Spring将对应的Bean对象注入到当前Bean中。

Spring依赖注入的方式有4种:

  • setter方法注入:通过调用setter方法注入属性

  • 构造方法注入/构造器注入:通过调用构造方法注入属性

  • 方法注入:通过调用普通的方法注入属性

  • 字段注入/属性注入:不需要调用方法就能完成注入

自动注入

自动注入指的是Spring对一个bean中的依赖的自动处理。

什么是依赖:一个Bean作为另外一个Bean的成员变量。

Spring有以下4种自动注入模式。

  • no:不自动注入(默认)

  • byType:通过类型注入,如果在当前IOC容器中有一个对应类型的Bean就会自动注入

  • byName:通过属性名自动注入

  • constructor:通过类型进行注入,但是要作为构造方法的参数

Spring默认是不会帮我们注入一个bean中的属性的,所以需要告诉Spring哪些属性需要进行注入。

配置文件

可以在xml配置文件中定义元配置(metadata configuration),通过beans标签的子标签bean及其子标签配置Bean的定义

beans标签

beans标签的标准格式如下:

<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"></beans>

<beans>标签上可以指定其<bean>子标签的默认属性:

标签属性属性说明取值范围
default-lazy-init默认的懒加载配置true、false
default-autowire默认的自动注入方式no、byType、byName、constructor
default-init-method默认的初始化方法任意方法名
default-destroy-method默认的销毁方法任意方法名

关于懒加载:

懒加载的bean只有第一次被访问时才会被Spring IOC容器创建。

在容器启动时不会创建懒加载的bean,直到第一次通过IOC容器获取使用这个bean。

bean标签

bean标签是beans标签的直接子标签,用来将一个类定义为Spring Bean。

bean标签上可以指定很多属性:

属性名属性说明默认值取值说明/取值范围
idbean ID任意的字符串,建议类名首字母小写
namebean名称任意的字符串,建议类名首字母小写
classbean的类型类的全限定名
scopebean的作用域singletonsingleton、prototype
autowire自动注入方式nono、byType、byName、constructor
lazy-init是否懒加载falsetrue、false
init-methodbean初始化完成调用的方法任意的方法名
depends-on依赖的Bean,被依赖的Bean会在当前Bean之前创建任意bean名称
factory-bean指定用于实例化bean的工厂Bean任意bean名称
factory-method指定用于实例化bean的工厂方法任意方法的方法名
destroy-methodbean销毁时调用的方法任意的方法名

实例化Bean

通过构造方法实例化

Spring IOC容器默认就是使用构造方法进行实例化的。

通过静态方法实例化

可以通过<bean/>的factory-method属性指定使用当前bean中定义的一个静态方法进行实例化(创建Bean对象)。

既然是用来创建对象的,这个静态方法的返回值类型就应该是Bean的类型。

package cn.edu.sgu.www.beans;import java.util.ArrayList;
import java.util.List;/*** @author heyunlin* @version 1.0*/
public class UserDao {public static UserDao newInstance() {System.out.println("调用UserDao.newInstance()...");return new UserDao();}public List<String> selectAll() {List<String> list = new ArrayList<>();list.add("Tom");list.add("Jhon");list.add("Marry");return list;}}

比如通过上面UserDao的newInstance()方法进行实例化。

<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="userDao" class="cn.edu.sgu.www.beans.UserDao" factory-method="newInstance"/>
</beans>

通过实例方法实例化

需要同时使用<bean/>的factory-bean和factory-method属性配置使用指定bean中定义的一个实例方法进行实例化(创建Bean对象)。

package cn.edu.sgu.www.beans;/*** @author heyunlin* @version 1.0*/
public class BeanInitializer {public UserDao newUserDao() {System.out.println("调用BeanInitializer.newUserDao()...");return new UserDao();}}

比如通过上面的BeanInitializer的newUserDao()方法实例化bean

<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="beanInitializer" class="cn.edu.sgu.www.beans.BeanInitializer" /><bean id="userDao" class="cn.edu.sgu.www.beans.UserDao"factory-bean="beanInitializer" factory-method="newUserDao"/>
</beans>

Bean的作用域

Bean的作用域(Scope)又叫Bean的作用范围,比如变量也有作用范围:成员变量(全局变量)、局部变量。

Spring中的bean默认都是单例(singleton)的。

  • 通过BeanFactory获取到的bean始终是同一个

  • Bean的作用范围是整个IOC容器

单例Bean的实现原理:

要实现这个效果,需要是用到软件设计模式中的单例模式(Singleton Desgn Pattern),就是将类的构造方法全部设置为私有,然后定义一个public的静态方法用于创建对象的实例。这个public的静态方法通常取名为newInstance()。

为什么是静态方法呢?构造方法被设置成了private,就无法去new对象了,所以就无法调用实例方法。

Spring中的作用域有以下几个:常用的就只有前两个。

作用域说明
singleton全局单例
prototype原型(多例),每次通过BeanFactory的getBean()方法获取到的bean都是一个新的对象
request一次HTTP请求就会创建一个Bean的实例
session一次session会话就会创建一个Bean的实例
application在一个应用中是单例的
websocket在一次WebSocket连接中是单例的

BeanDefinition

BeanDefinition叫做Bean的定义,保存了Bean的信息(名称、类型等)

beans标签的所有bean子标签都会被解析为一个BeanDefinition对象。

这个接口中定义了大量和bean标签属性对应的许多getter、setter方法。

package org.springframework.beans.factory.config;public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {// 和bean标签属性对应的许多getter、setter方法...
}

AbstractBeanDefinition

BeanDefinition是一个接口,实际使用的是其派生类AbstractBeanDefinition。

package org.springframework.beans.factory.support;public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessorimplements BeanDefinition, Cloneable {@Nullableprivate volatile Object beanClass; // class@Nullableprivate String scope = SCOPE_DEFAULT; // scope@Nullableprivate Boolean lazyInit; // lazy-initprivate int autowireMode = AUTOWIRE_NO; // autowire@Nullableprivate String[] dependsOn; // depends-onprivate boolean autowireCandidate = true; // autowire-candidateprivate boolean primary = false; // primary@Nullableprivate String factoryBeanName; // factory-bean@Nullableprivate String factoryMethodName; // factory-method@Nullableprivate String initMethodName; // init-method@Nullableprivate String destroyMethodName; // destroy-method// 其他属性...// getter、setter方法...
}

Spring IOC容器会根据这些BeanDefinition对象来创建Bean,然后保存起来。

在容器启动完成后,就可以通过代表IOC容器的接口BeanFactory、ApplicationContext获取bean了。

回调接口

Spring提供了大量和bean的生命周期相关的回调接口。

Aware

Aware是Spring的回调接口,Aware接口有很多的子接口,这些接口下通常就定义了一个set方法。

BeanNameAware

可以通过BeanNameAware获取Bean名称。

package org.springframework.beans.factory;public interface BeanNameAware extends Aware {/*** 设置Bean名称*/void setBeanName(String name);
}

BeanFactoryAware

可以通过BeanFactoryAware获取BeanFactory。

package org.springframework.beans.factory;import org.springframework.beans.BeansException;public interface BeanFactoryAware extends Aware {/*** 设置BeanFactory*/void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}

ApplicationContextAware

可以通过ApplicationContextAware获取ApplicationContext。

package org.springframework.context;import org.springframework.beans.factory.Aware;public interface ApplicationContextAware extends Aware {/*** 设置ApplicationContext*/void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

ApplicationEventPublisherAware

可以通过ApplicationEventPublisherAware获取ApplicationEventPublisher(事件发布器)。

package org.springframework.context;import org.springframework.beans.factory.Aware;public interface ApplicationEventPublisherAware extends Aware {	void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher);
}

InitializingBean

InitializingBean叫做初始化bean,是Spring的bean初始化回调接口。

通过InitializingBean,可以在bean初始化完成(通过自动注入设置完属性)后,对bean进行一些操作。

package org.springframework.beans.factory;public interface InitializingBean {void afterPropertiesSet() throws Exception;
}

接下来自定义一个InitializingBean,在所有bean初始化完成后打印提示。

package cn.edu.sgu.www.beans;import org.springframework.beans.factory.InitializingBean;/*** @author heyunlin* @version 1.0*/
public class CutomInitializingBean implements InitializingBean {@Overridepublic void afterPropertiesSet() {System.out.println("完成属性注入...");}}

这个接口的作用和bean标签通过init-method属性指定方法是一样的。

DisposableBean

DisposableBean叫做销毁bean,是Spring的bean销毁回调接口。

package org.springframework.beans.factory;public interface DisposableBean {void destroy() throws Exception;
}

通过DisposableBean,可以在bean被销毁后执行一些操作。

这个接口的作用和bean标签通过destroy-method属性指定方法是一样的。

容器扩展

BeanPostProcessor

BeanPostProcessor叫做bean的后置处理器,通过BeanPostProcessor可以在bean实例化过程中对bean进行修改。

package org.springframework.beans.factory.config;import org.springframework.beans.BeansException;
import org.springframework.lang.Nullable;public interface BeanPostProcessor {@Nullabledefault Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}@Nullabledefault Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}}

BeanPostProcessor接口中定义了两个默认的方法(根据需要重写)

  • postProcessBeforeInitialization()

  • postProcessAfterInitialization()

postProcessBeforeInitialization()

在bean实例化之前对bean进行修改。

postProcessAfterInitialization()

在bean实例化之后对bean进行修改。

自定义BeanPostProcessor

自定义一个BeanPostProcessor完成bean的属性的设置(类似依赖注入)。

package cn.edu.sgu.www.beans;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.support.ClassPathXmlApplicationContext;import java.lang.reflect.Field;/*** @author heyunlin* @version 1.0*/
public class CustomBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if ("userController".equals(beanName)) {Field[] fields = bean.getClass().getDeclaredFields();for (Field field : fields) {field.setAccessible(true);try {Object value = field.get(bean);Object instance = field.getType().newInstance();if (value == null) {field.set(bean, instance);}} catch (Exception e) {e.printStackTrace();}}}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}}

这种方式是直接通过反射创建bean对象,而不是通过BeanFactory获取。

执行postProcessBeforeInitialization()方法时所有bean都还没有完成初始化。

BeanFactoryPostProcessor

BeanFactoryPostProcessor叫做bean工厂的后置处理器,通过BeanFactoryPostProcessor可以修改bean的定义。

package org.springframework.beans.factory.config;import org.springframework.beans.BeansException;@FunctionalInterface
public interface BeanFactoryPostProcessor {void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

BeanFactoryPostProcessor的执行时机是,所有bean的定义都已经加载完成,但是还没有实例化。

使用IOC容器

创建项目

在Intellij IDEA中创建一个maven项目spring-study

添加依赖

使用Spring的IOC/DI特性需要引入spring-beans和spring-context两个依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>cn.edu.sgu.www</groupId><artifactId>spring-study</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>5.2.9.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.9.RELEASE</version></dependency></dependencies>
</project>

创建对象

在项目的src/java目录下创建多级包cn.edu.sgu.www

在cn.edu.sgu.www包下创建beans包

UserDao.java

在beans包下创建一个类UserDao

package cn.edu.sgu.www.beans;import java.util.ArrayList;
import java.util.List;/*** @author heyunlin* @version 1.0*/
public class UserDao {public List<String> selectAll() {List<String> list = new ArrayList<>();list.add("Tom");list.add("Jhon");list.add("Marry");return list;}}

UserService.java

在beans包下创建一个类UserService

package cn.edu.sgu.www.beans;import java.util.List;/*** @author heyunlin* @version 1.0*/
public class UserService {private UserDao userDao;public void setUserDao(UserDao userDao) {this.userDao = userDao;}public List<String> selectAll() {return userDao.selectAll();}}

UserController.java

在beans包下创建一个类UserController

package cn.edu.sgu.www.beans;import java.util.List;/*** @author heyunlin* @version 1.0*/
public class UserController {private final UserService userService;public UserController(UserService userService) {this.userService = userService;}public List<String> selectAll() {return userService.selectAll();}}

创建配置文件

在类路径(resouces)目录下创建一个beans目录,然后在bean目录下Spring的xml配置文件。

daos.xml
<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="userDao" class="cn.edu.sgu.www.beans.UserDao" />
</beans>

services.xml

通过UserService配置依赖注入(setter注入)

<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="userService" class="cn.edu.sgu.www.beans.UserService"><property name="userDao" ref="userDao" /></bean>
</beans>

注意,使用setter注入方式时,需要保证对应的bean上声明了无参构造方法和对应属性的setter方法。

controllers.xml

通过UserController配置依赖注入(构造方法注入)

<?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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="userController" class="cn.edu.sgu.www.beans.UserController"><constructor-arg ref="userService" type="cn.edu.sgu.www.beans.UserService" /></bean>
</beans>

注意,使用构造方法注入方式时,需要保证对应的bean上声明了对应属性的有参构造方法。

通过IOC容器获取Bean

IOC容器相关接口
BeanFactory

BeanFactory接口提供了一种高级配置机制,能够管理任何类型的对象。

其中,有几个重载的getBean()方法可以从Spring IOC容器中获取bean。

package org.springframework.beans.factory;import org.springframework.beans.BeansException;public interface BeanFactory {/*** 通过bean名称获取bean*/Object getBean(String name) throws BeansException;Object getBean(String name, Object... args) throws BeansException;/*** 通过bean的类型获取bean*/<T> T getBean(Class<T> requiredType) throws BeansException;<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;/*** 通过bean名称和类型获取bean*/<T> T getBean(String name, Class<T> requiredType) throws BeansException;
}

和BeanFactory接口名字及其相似的一个接口FactoryBean,叫做工厂bean。

工厂bean通常作为一个bean工厂,负责创建bean对象。

package org.springframework.beans.factory;public interface FactoryBean<T> {Class<?> getObjectType();T getObject() throws Exception;default boolean isSingleton() {return true;}
}

ApplicationContext

ApplicationContext是BeanFactory的子接口。

package org.springframework.context;import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.core.env.EnvironmentCapable;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.lang.Nullable;public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {@NullableString getId();/*** 获取启动时间*/long getStartupDate();/*** 获取当前应用上下文的名称*/String getDisplayName();/*** 获取应用名称*/String getApplicationName();/*** 获取上一级应用上下文*/@NullableApplicationContext getParent();/*** 获取AutowireCapableBeanFactory*/AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}

相比于BeanFactory,ApplicationContext中新增了以下功能:

  • 更容易与Spring的AOP功能集成

  • 消息资源处理(用于国际化internationalization, i18n)——实现了MessageSource接口

  • 事件发布——实现了ApplicationEventPublisher接口

  • 特定于应用层的上下文(ApplicationContext提供的不同应用场景下使用的派生类)

    • 比如Web应用程序中使用的WebApplicationContext

ApplicationContext有以下几个常用的派生类:

ClassPathXmlApplicationContext

ClassPathXmlApplicationContext用于通过类路径(classpath)下的xml配置文件创建ApplicationContext对象。

使用ClassPathXmlApplicationContext时,只需要指定相对于项目的src/main/resources路径下的文件位置。

例如:通过src/main/resources/beans.xml配置文件创建ApplicationContext对象。

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans/daos.xml");

FileSystemXmlApplicationContext

用于通过文件系统的xml配置文件创建ApplicationContext对象,通过FileSystemXmlApplicationContext可以加载项目外的xml文件。

使用FileSystemXmlApplicationContext时,需要指定xml文件的绝对路径(因此,可以加载项目外的配置文件)。

String path = "D:/program/IdeaProjects/spring-study/src/main/resources/bean/beans.xml";ApplicationContext applicationContext = new FileSystemXmlApplicationContext(path);

AnnotationConfigApplicationContext

用于通过配置类创建ApplicationContext对象,后面使用注解方式配置Bean的时候会讲。

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(CustomConfig.class);

通过BeanFactory获取Bean

在cn.edu.sgu.www包下创建XmlBasedSpringExample类,用来写获取Bean的Java代码。

获取UserDao
package cn.edu.sgu.www;import cn.edu.sgu.www.beans.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** @author heyunlin* @version 1.0*/
public class XmlBasedSpringExample {public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans/daos.xml");// 通过Bean名称获取BeanObject bean = applicationContext.getBean("userDao");if (bean instanceof UserDao) {UserDao userDao = (UserDao) bean;System.out.println(userDao.selectAll());}// 通过类型获取BeanUserDao userDao = applicationContext.getBean(UserDao.class);System.out.println(userDao.selectAll());}}

获取UserService
package cn.edu.sgu.www;import cn.edu.sgu.www.beans.UserDao;
import cn.edu.sgu.www.beans.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** @author heyunlin* @version 1.0*/
public class XmlBasedSpringExample {public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans/daos.xml", "bean/services.xml");// 通过Bean名称获取BeanObject bean = applicationContext.getBean("userService");if (bean instanceof UserService) {UserService userService = (UserService) bean;System.out.println(userService.selectAll());}// 通过类型获取BeanUserService userService = applicationContext.getBean(UserService.class);System.out.println(userService.selectAll());}}

获取UserController
package cn.edu.sgu.www;import cn.edu.sgu.www.beans.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** @author heyunlin* @version 1.0*/
public class XmlBasedSpringExample {public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans/daos.xml", "bean/services.xml", "bean/controllers.xml");// 通过Bean名称获取BeanObject bean = applicationContext.getBean("userController");if (bean instanceof UserController) {UserController userController = (UserController) bean;System.out.println(userController.selectAll());}// 通过类型获取BeanUserController userController = applicationContext.getBean(UserController.class);System.out.println(userController.selectAll());}}

获取所有Spring Bean
package cn.edu.sgu.www;import cn.edu.sgu.www.beans.UserController;
import cn.edu.sgu.www.beans.UserDao;
import cn.edu.sgu.www.beans.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** @author heyunlin* @version 1.0*/
public class XmlBasedSpringExample {public static void main(String[] args) {getUserDao();getUserService();getUserController();}private static void getUserDao() {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans/daos.xml");// 通过Bean名称获取BeanObject bean = applicationContext.getBean("userDao");if (bean instanceof UserDao) {UserDao userDao = (UserDao) bean;System.out.println(userDao.selectAll());}// 通过类型获取BeanUserDao userDao = applicationContext.getBean(UserDao.class);System.out.println(userDao.selectAll());}private static void getUserService() {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans/daos.xml", "beans/services.xml");// 通过Bean名称获取BeanObject bean = applicationContext.getBean("userService");if (bean instanceof UserService) {UserService userService = (UserService) bean;System.out.println(userService.selectAll());}// 通过类型获取BeanUserService userService = applicationContext.getBean(UserService.class);System.out.println(userService.selectAll());}private static void getUserController() {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans/daos.xml", "beans/services.xml", "beans/controllers.xml");// 通过Bean名称获取BeanObject bean = applicationContext.getBean("userController");if (bean instanceof UserController) {UserController userController = (UserController) bean;System.out.println(userController.selectAll());}// 通过类型获取BeanUserController userController = applicationContext.getBean(UserController.class);System.out.println(userController.selectAll());}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/33553.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

架构学习第八周--Kubernetes博客搭建

目录 一、整体架构 二、部署MySQL主从 三、部署Redis哨兵 四、部署WordPress 五、注意事项 一、整体架构 本项目为在一主三从的Kubernetes集群上部署WordPress博客。因为WordPress部分容器版本自行集成Apache和PHP服务&#xff0c;因此在Kubernetes上部署WordPress只需提供…

【品铂科技】在高精度定位行业内的口碑怎么样?

1. ‌技术实力与行业认可‌ 公司自主研发的ABELL无线实时定位系统在复杂环境中&#xff08;如工业、司法监狱等&#xff09;展现出厘米级&#xff08;5-10厘米&#xff09;高精度定位能力&#xff0c;客户反馈系统稳定性强、抗干扰能力突出&#xff0c;成为行业技术标杆‌。参…

长度最小的子数组-滑动窗口解法

本来觉得自己双指针学的还可以了&#xff0c;于是今天直接刷了一道滑动窗口题&#xff0c;没想到还是被坑绊倒了两次。这次我想记录在博客里&#xff0c;不仅可以防止我以后重蹈覆辙&#xff0c;兴许也还可以帮助到其他人。 题目来自力扣&#xff1a;209. 长度最小的子数组 - …

深入理解Linux网络随笔(七):容器网络虚拟化--Veth设备对

深入理解Linux网络随笔&#xff08;七&#xff09;&#xff1a;容器网络虚拟化 微服务架构中服务被拆分成多个独立的容器&#xff0c;docker网络虚拟化的核心技术为&#xff1a;Veth设备对、Network Namespace、Bridg。 Veth设备对 veth设备是一种 成对 出现的虚拟网络接口&…

深入理解 Maven BOM 及其继承特性

深入理解 Maven BOM 及其继承特性 一、什么是 Maven BOM&#xff1f; Maven BOM&#xff08;Bill Of Materials&#xff0c;物料清单&#xff09;是一种特殊的 Maven 项目&#xff0c;用于集中管理依赖项的版本信息。BOM 项目本身并不包含实际的代码或资源&#xff0c;而仅仅…

C语言(25)

一.数据在内存中的存储 1.整数在内存中的存储 整数在内存中以二进制的形式储存&#xff0c;分别为原码&#xff0c;补码&#xff0c;反码 有符号的整数&#xff0c;在上述三种形式都有符号位和数值位两个部分&#xff0c;符号位为0是正数&#xff0c;1是负数&#xff0c;最高…

一篇博客搞定时间复杂度

时间复杂度 1、什么是时间复杂度&#xff1f;2、推导大O的规则3、时间复杂度的计算3.1 基础题 13.2 基础题 23.3基础题 33.4进阶题 13.5进阶题 23.6 偏难题 13.7偏难题 2&#xff08;递归&#xff09; 前言&#xff1a; 算法在编写成可执行程序后&#xff0c;运行时要耗费时间和…

探索 Trossen AI:从 Aloha到智能机器人平台的进化之路

在人工智能与机器人技术快速发展的当下&#xff0c;科研硬件的性能与成本成为影响行业创新的重要因素。Trossen Robotic为在机器人领域二十余年的知名企业&#xff0c;近日推出的 Trossen AI 系列产品&#xff0c;为科研机构与开发者提供了高性能、高性价比的解决方案。 Trosse…

【Power Platform系列】如何在画布应用中调用工作流上传附件

在Power Apps画布应用中上传附件&#xff0c;比如到SharePoint文档库最典型的方式非常简单&#xff0c;插入一个编辑窗体&#xff0c;将窗体和背后的文档库绑定起来即可以快速实现。不过窗体内部的显示格式很难控制&#xff0c;如果要实现更为灵活的控制&#xff0c;就需要采用…

工作记录 2017-01-12

序号 工作 相关人员 1 协助BPO进行Billing的工作。 处理Amazing Charts的数据查询。 修改BillingJobPoster&#xff0c;处理CCDA 的自动导入&#xff0c;预计还需一天才能完成。 修改录入Code的界面&#xff08;code 移动到指定位置&#xff09;&#xff0c;预计明天更新。…

在centOS Linux系统搭建自动化构建工具Jenkins

前言 在工作中发现公司使用Jenkins实现自动化部署项目方案&#xff0c;于是闲着自己也捣鼓一下&#xff0c;网上查阅相关部署资料&#xff0c;顺便记录操作步骤&#xff0c;所以有了下面这篇的文章。 部署完之后&#xff0c;安装前端项目所需环境&#xff0c;比如node环境&am…

开箱即用的whisper-service服务

安装须知 Whisper官方网址 https://github.com/openai/whisper Whisper 镜像站 https://docker.aityp.com/r/docker.io/onerahmet 本次提供的环境镜像为&#xff1a;docker.io/onerahmet/openai-whisper-asr-webservice:v1.6.0-gpu 运行环境要求 服务器架构 服务器架构要…

SpringCloud带你走进微服务的世界

认识微服务 随着互联网行业的发展&#xff0c;对服务的要求也越来越高&#xff0c;服务架构也从单体架构逐渐演变为现在流行的微服务架构。这些架构之间有怎样的差别呢&#xff1f; 单体架构 单体架构&#xff1a;将业务的所有功能集中在一个项目中开发&#xff0c;打成一个…

【xv6操作系统】页表与写时拷贝解析及相关实验设计

【xv6操作系统】页表与写时拷贝解析及相关实验设计 页表页表概念xv6页表xv6 TLB实验1&#xff1a;加速系统调用实验2&#xff1a;打印三级页表实验3&#xff1a;检测已访问的页表 写时拷贝写时拷贝实验实现 页表 页表概念 deepseek说&#xff1a; 页表&#xff08;Page Table…

如何处理PHP中的编码问题

如何处理PHP中的编码问题 在PHP开发过程中&#xff0c;编码问题是一个常见且棘手的问题。无论是处理用户输入、数据库交互&#xff0c;还是与外部API通信&#xff0c;编码问题都可能导致数据乱码、解析错误甚至安全漏洞。本文将深入探讨PHP中的编码问题&#xff0c;并提供一些…

人工智能之数学基础:线性变换的象空间和零空间

本文重点 前面的课程中,我们学习了线性变换,由此而引申出线性变换的象空间和零空间,这两个空间在机器学习领域会被经常用到,本文对此进行学习。 直观理解 总的来说象空间就是经过线性变换得到的空间,零空间就是经过线性变换是零的元素构成的空间。 从几何角度来看,象空…

方案精读:IBM方法论-IT规划方法论

该文档聚焦 IT 规划方法论&#xff0c;适合企业高层管理者、IT 部门负责人、业务部门主管以及参与企业信息化建设的相关人员阅读。 &#xff08;本解读资料已包含在绑定资源内&#xff09; 主要内容围绕 IT 规划展开&#xff1a;首先明确 IT 规划需基于企业核心战略&#xff0…

日志监控工具openobserve使用案例

引言 分享一个日志监控工具&#xff0c;openobserve&#xff08;简称 o2&#xff09;&#xff0c;它是一个云原生可观察性平台&#xff0c;专为日志、指标、跟踪、分析 而构建&#xff0c;旨在以 PB 级规模运行。与 Elasticsearch 不同&#xff0c;OpenObserve 不需要了解和调整…

基于威胁的安全测试值得关注,RASP将大放异彩

2‍021年7月21日&#xff0c;由中国信息通信研究院&#xff08;CAICT&#xff09;指导、悬镜安全主办、腾讯安全协办的中国首届DevSecOps敏捷安全大会&#xff08;DSO 2021&#xff09;在北京圆满举办。大会以“安全从供应链开始”为主题&#xff0c;寓意安全基础决定“上层建筑…

Flutter项目升级Xcode 16.2之后编译问题

最近好久没升级Xcode了&#xff0c;升级了一下最新的16.2之后。发现Flutter项目在iOS设备上运行不起来了。报错&#xff1a; 查了许多网友也遇到了&#xff0c;其中一个解决方案&#xff1a;https://stackoverflow.com/questions/79118572/xcode-16-and-ios-18-project-not-com…