Spring的核心是IoC(Inversion of Control,控制反转)容器,它可以管理容器内的普通Java对象以及对象之间关系的绑定(Dependency Injection依赖注入)。容器中被管理的对象称为Bean。
Spring是通过元数据和POJO来定义和管理Bean的。
◎POJO:简单的Java对象。
◎元数据:描述如何管理POJO的数据。
当使用了@Compoent,@Service,@Controller,@Repository时,Spring容器(@CompoentScan实现)会自动扫描,并将他们注册成被容器管理的Bean.
@Service、@Repository和@Controller这三个注解组合了@Component注解,它们是@Component语义上的特例。
在类上注解@Configuration(@Component的特例,会被容器自动扫描),可使类成为配置类。如果使用@Bean标注在类的方法上,则方法的返回值即为Bean的实例。
1.注解注入-直接注入类:在类的属性上添加@Autowired注解,即可获取容器中的Bean对象.
@Component
public class SpringTestDI {
public void di(){
System.out.println("已注入Bean的方法");
}
}
@SpringBootTest
@Component
public class SpringAuto {
@Autowired
private SpringTestDI springTestDI;
@Test
public void autoPoint(){
this.springTestDI.di();
}
}
2.注解注入-注入方法:加在方法上,注册Bean的时候会自动依赖注入
@Component
public class SpringTestDI {
public void di(){
System.out.println("已注入Bean的方法");
}
}
@Component
@Data
public class SpringAuto {
private SpringTestDI springTestDI;
@Autowired
public void autoPoint(SpringTestDI springTestDI){
this.springTestDI = springTestDI;
}
}
@SpringBootTest
public class SpringTest {
@Autowired
private SpringAuto springAuto;
@Test
public void xxx(){
SpringTestDI springTestDI = springAuto.getSpringTestDI();
springTestDI.di();
}
}
3.注解注入-构造方法:加在构造方法上依赖注入,只有一个构造方法可以默认不写@Autowired
@SpringBootTest
@Component
@Data
public class SpringAuto {
private SpringTestDI springTestDI;
public SpringAuto(SpringTestDI springTestDI){
this.springTestDI = springTestDI;
}
}
使用@Autowired注解是根据类型自动注入的,当两个类型相同时,无法正确注入,可以使用@Primary注解来确定注入哪一个Bean
@Configuration
public class SpringPrimary {
@Bean
public SpringAuto a(){
System.out.println("a");
return new SpringAuto("a");
}
@Primary
@Bean
public SpringAuto b(){
System.out.println("b");
return new SpringAuto("b");
}
}
通过指定名称来确定依赖注入的bean
@Configuration
public class SpringPrimary {
@Bean("a")
public SpringAuto a(){
System.out.println("a");
return new SpringAuto("a");
}
@Bean("b")
public SpringAuto b(){
System.out.println("b");
return new SpringAuto("b");
}
}
@Autowired
@Qualifier("a")
private SpringAuto springAuto;
是Spring Boot框架提供的一个接口,主要用于应用启动后立即执行特定的业务逻辑。当一个类实现了 CommandLineRunner
接口,Spring Boot将会自动检测并运行该类的 run
方法。这对于一些初始化任务或者一次性执行的任务非常有用,比如读取配置文件、数据预加载、初始化缓存等。
@Component
public class SpringCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("SpringBoot项目启动完成,我来前面探探路");
}
}
指定Bean的作用域,默认是单例模式,整个容器只有一个相同类型的bean
/**
* 原型Prototype 每次都会创建一个新的实例
*/
@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class SpringScope {
}
@SpringBootTest
public class SpringTest {
@Autowired
private SpringScope springScope1;
@Autowired
private SpringScope springScope2;
@Test
public void xxx(){
// 结果:false; 默认不使用Scope注解,结果为true
System.out.println(springScope1 == springScope2);
}
}
先了解简单的生命周期,以下是顺序执行
@Component
public class SpringLife {
public SpringLife() {
System.out.println("bean的构造方法");
}
@PostConstruct
public void init(){
System.out.println("bean的初始化方法");
}
@PreDestroy
public void destroy(){
System.out.println("bean的销毁方法");
}
}
延迟初始化:再被调用的时候才会初始化,需要已常见四大组件注解搭配使用
可以控制依赖注入的先后顺序
@Enable*
注解系列: Spring框架提供了一系列以 @Enable
开头的注解,这些注解用于启用特定的功能模块或框架特性。例如:
@EnableAspectJAutoProxy
:启用Spring AOP代理和AspectJ切面自动代理功能。@EnableCaching
:启用Spring的缓存支持。@EnableScheduling
:启用定时任务调度功能。@EnableTransactionManagement
:启用Spring的事务管理支持。@EnableWebMvc
:在Spring MVC应用中启用注解驱动的Web MVC配置。这些注解通常放在一个配置类上,Spring在扫描和解析配置时会识别到这些注解,并加载相应的配置处理器来处理它们。
@Import
注解用于将其他配置类或配置类的全限定名导入到当前配置类中。当Spring容器加载包含 @Import
注解的配置类时,也会加载并处理被导入的配置类。这样可以实现多个配置类的整合和复用。
@Configuration
@Import({DatabaseConfig.class, ServiceConfig.class, WebConfig.class})
public class AppConfig {
// ...
}
可以通过实现BeanPostProcessor接口,在构造时对容器内所有或者部分指定Bean进行处理。和@PostConstruct与@PreDestroy不同的是,它针对的是IoC容器里的所有的Bean。
postProcessBeforeInitialization(Object bean, String beanName)
: 这个方法会在Spring容器对Bean实例化并设置好所有属性后,但在调用该Bean的初始化方法(如InitializingBean.afterPropertiesSet()
或者带有 @PostConstruct
注解的方法)之前调用。在该方法中,开发者可以对刚实例化的Bean进行进一步的加工或修改。postProcessAfterInitialization(Object bean, String beanName)
: 这个方法会在Bean的初始化方法调用完毕后,但在Bean正式交付给Spring容器使用之前调用。开发者可以在该方法中对已经初始化完成的Bean做进一步的处理,例如AOP代理增强、日志记录等。public class PostProcessorTest implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("属性设置之后,Bean初始化之前:" + beanName + "]");
// 可以对bean进行某些操作,例如AOP代理、属性修改等
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean初始化之后: [" + beanName + "]");
// 同样可以对bean进行更多后期处理
return bean;
}
}
Spring Aware 是Spring框架中一系列接口的总称,这些接口允许Spring容器在实例化和初始化Bean的过程中向Bean注入特定的资源或信息。实现这些Aware接口的类能够感知Spring容器的存在,并通过Spring容器获取相应的服务或上下文。
◎BeanNameAware:可获得beanName,即Bean的名称。
◎ResourceLoaderAware:可获得ResourceLoader,即用来加载资源的Bean。
◎BeanFactoryAware:可获得BeanFactory,即容器的父接口,用于管理Bean的相关操作。
◎EnvironmentAware:可获得Environment,即当前应用的运行环境。
◎MessageSourceAware:可获得MessageSource,即用来解析文本信息的Bean。
◎ApplicationEventPublisherAware:可获得ApplicationEventPublisher,即用来发布系统时间的Bean。
◎ApplicationContextAware:可自动注入ApplicationContext,即容器本身。
如果Bean之间需要通信,比如说BeanA完成了处理后需要告知BeanB,通知BeanB继续处理,那么我们称BeanA为Publisher,称BeanB为Listener。
/**
* 事件类
* @Author : MengYansong
* @create 2024/1/29 15:53
*/
public class MyEvent extends ApplicationEvent {
public MyEvent(Object source) {
super(source);
}
}
/**
* 发布事件
*/
@Component
public class EventPublisher {
private final ApplicationContext context;
@Autowired
public EventPublisher(ApplicationContext context) {
this.context = context;
}
public void fireEvent() {
System.out.println("1.发布事件");
context.publishEvent(new MyEvent(this));
}
}
/**
* 事件监听
*/
@Component
public class MyEventListener implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) {
// 在这里处理事件逻辑
System.out.println("2.监听事件: " + event);
}
}
Spring EL(Spring Expression Language,Spring表达式语言)是Spring生态下的通用语言,在运行时使用表达式查询属性信息(使用符号$)或操作Java对象(使用符号#),主要用在XML或注解上。
@SpringBootTest
public class SpringTest {
@Autowired
private EventPublisher eventPublisher;
@Value("${yyds.y1}")
private String name;
@Test
public void xxx(){
System.out.println(name);
}
}
yyds:
y1: 666
y2: 777