基础环境与文档资料:

见黑马视频:

https://www.bilibili.com/video/BV1P44y1N7QG

依赖坐标:

<?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.cloud9</groupId>
<artifactId>Spring5</artifactId>
<version>1.0-SNAPSHOT</version> <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
</dependencies>
</project>

  

一、ApplicationContext接口

package cn.cloud9;

import cn.cloud9.bean.Component1;
import cn.cloud9.event.UserRegisteredEvent;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultSingletonBeanRegistry;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.Resource; import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map; /**
* @projectName: Spring5
* @author: OnCloud9
* @date: 2023年02月07日 09:13
* @version: 1.0
*/
@Slf4j
@SpringBootApplication
public class MainApplication { @SneakyThrows
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(MainApplication.class, args);
log.info("ConfigurableApplicationContext -> {}", applicationContext); /*
* ApplicationContext的功能
* 1、I18N支持, MessageSource接口实现
* - 默认读取的配置文件:messages.properties
* - 指定文件文件名称 中文zh 英文en 日文ja
*/
String cnHello = applicationContext.getMessage("hello", null, Locale.CHINA);
String enHello = applicationContext.getMessage("hello", null, Locale.ENGLISH);
String jpHello = applicationContext.getMessage("hello", null, Locale.JAPANESE);
log.info("I18N 国际化参数读取 CN -> {}, EN -> {}, JP -> {}", cnHello, enHello, jpHello); /*
* ApplicationContext的功能
* 2、读取类路径下的资源
* - classpath: * 读取当前项目下的类路径资源
* - classpath*: * 读取项目所有依赖下的类路径
*/
Resource[] resources = applicationContext.getResources("classpath:*");
Arrays.stream(resources).forEach(resource -> log.info("classpath: -> {}", resource)); resources = applicationContext.getResources("classpath*:*");
Arrays.stream(resources).forEach(resource -> log.info("classpath*: -> {}", resource)); // 获取Spring的SPI配置文件
resources = applicationContext.getResources("classpath*:META-INF/spring.factories");
Arrays.stream(resources).forEach(resource -> log.info("META-INF/spring.factories: -> {}", resource)); /*
* ApplicationContext的功能
* 3、读取配置文件的值
*/
ConfigurableEnvironment environment = applicationContext.getEnvironment(); // 系统变量 + 配置文件
String javaHome = environment.getProperty("java_home");
String serverPort = environment.getProperty("server.port");
log.info("javaHome -> {}, serverPort -> {}", javaHome, serverPort); /*
* ApplicationContext的功能
* 4、发布事件
* - 发布事件的意义是为了解耦业务逻辑
*/ // 1、使用ApplicationContext直接发布事件
UserRegisteredEvent userRegisteredEvent = new UserRegisteredEvent(applicationContext);
applicationContext.publishEvent(userRegisteredEvent); // 2、使用Bean对象发布事件
Component1 component1 = applicationContext.getBean("component1", Component1.class);
component1.registerBusinessAction();
}
}

I18N国际化配置文件:

  

UserRegisteredEvent事件源类:

package cn.cloud9.event;

import org.springframework.context.ApplicationEvent;

/**
* 用户注册事件类
* @author OnCloud9
* @version 1.0
* @project Spring5
* @date 2023年02月08日 10:45
*/
public class UserRegisteredEvent extends ApplicationEvent {
/**
* Create a new {@code ApplicationEvent}.
*
* @param source the object on which the event initially occurred or with
* which the event is associated (never {@code null})
*/
public UserRegisteredEvent(Object source) {
super(source);
}
}

在Component2类的监听方法:

package cn.cloud9.bean;

import cn.cloud9.event.UserRegisteredEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component; /**
* @projectName: Spring5
* @author: OnCloud9
* @date: 2023年02月07日 09:30
* @version: 1.0
*/
@Slf4j
@Component
public class Component2 { /**
* @author OnCloud9
* @date 2023/2/8 11:01
* @description
* @params [event]
* @return void
*/
@EventListener
public void receiveEvent(UserRegisteredEvent event) {
log.info("用户注册事件触发, 监听方法执行!!!!");
}
}

  

Component1中的发布事件方法:

package cn.cloud9.bean;

import cn.cloud9.event.UserRegisteredEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component; import javax.annotation.Resource; /**
* @projectName: Spring5
* @author: OnCloud9
* @date: 2023年02月07日 09:30
* @version: 1.0
*/
@Slf4j
@Component
public class Component1 { @Resource
private ApplicationEventPublisher applicationEventPublisher; /**
* @author OnCloud9
* @date 2023/2/8 11:06
* @description 用户注册业务行为
* @params []
* @return void
*/
public void registerBusinessAction() {
log.info("用户注册业务行为开始!");
applicationEventPublisher.publishEvent(new UserRegisteredEvent(this));
}
}

  

启动时打印信息:

2023-02-08 14:36:50.523  INFO 6548 --- [           main] cn.cloud9.bean.Component2                : 用户注册事件触发, 监听方法执行!!!!
2023-02-08 14:36:50.524 INFO 6548 --- [ main] cn.cloud9.bean.Component1 : 用户注册业务行为开始!
2023-02-08 14:36:50.524 INFO 6548 --- [ main] cn.cloud9.bean.Component2 : 用户注册事件触发, 监听方法执行!!!!

二、BeanFactory接口

/*
* BeanFactory
* 1、是ApplicationContext的父接口
* 2、是Spring的核心容器
* 3、ApplicationContext组合了BeanFactory的功能
* 4、获取Bean对象,控制反转,依赖注入,Bean的生命周期的各种功能,由BeanFactory的实现类完成
*/
Field field = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
field.setAccessible(true);
ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
Map<String,Object> beanTanker = (Map<String,Object>)field.get(beanFactory);
beanTanker.entrySet().stream().filter(e -> e.getKey().startsWith("component")).forEach(e -> {
  log.info("key -> {}, value -> {}", e.getKey(), e.getValue());
});

  

import cn.cloud9.MainApplication;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringRunner; import javax.annotation.Resource;
import java.util.Map; /**
* @author OnCloud9
* @version 1.0
* @project Spring5
* @date 2023年02月08日 11:12
*/
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MainApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class BeanFactoryTest { /**
* @author OnCloud9
* @date 2023/2/8 13:47
* BeanFactory
* - 不会主动调用BeanFactory的后置处理器
* - 不会主动调用Bean的后置处理器
* - 不会主动初始化单例Bean对象
* - 不会解析BeanFactory, 包括${} #{} 值注入
* Bean的后处理有排序逻辑
*
*/
@Test
public void beanInitializeProcess() {
/*
* Bean的定义, 初始化, scope, 销毁,
*/
final DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); /* 1、生成Bean的定义对象 */
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition(); /* 2、Bean工厂注册定义对象 */
beanFactory.registerBeanDefinition("config", beanDefinition); /* 3、获取注册的Bean定义名称集合 */
String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) log.info("beanDefinitionName: {}", beanDefinitionName);
} @Configuration
static class Config { @org.springframework.context.annotation.Bean
public Bean1 bean1() {
return new Bean1();
} @org.springframework.context.annotation.Bean
public Bean2 bean2() {
return new Bean2();
}
} @Data
private static class Bean1 {
@Autowired
private Bean2 bean2;
} private static class Bean2 {} }

  

在注册Bean定义对象之后

beanFactory.registerBeanDefinition("config", beanDefinition);

BeanFactory对象中只有当前这个config的Bean定义对象

一些自动装配注解,事件监听需要后置处理器的加入:

/* 4、添加一些常用的后处理器 */
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
/*
* org.springframework.context.annotation.internalConfigurationAnnotationProcessor
* org.springframework.context.annotation.internalAutowiredAnnotationProcessor
* org.springframework.context.annotation.internalCommonAnnotationProcessor
* org.springframework.context.event.internalEventListenerProcessor
* org.springframework.context.event.internalEventListenerFactory
*/
log.info("添加后置处理器后...");
beanDefinitionNames = beanFactory.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) log.info("beanDefinitionName : {}", beanDefinitionName);

打印结果:

2023-02-08 14:54:26.964  INFO 33432 --- [           main] BeanFactoryTest                          : 添加后置处理器后...
2023-02-08 14:54:26.964 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: config
2023-02-08 14:54:26.965 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
2023-02-08 14:54:26.965 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
2023-02-08 14:54:26.965 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: org.springframework.context.annotation.internalCommonAnnotationProcessor
2023-02-08 14:54:26.965 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: org.springframework.context.event.internalEventListenerProcessor
2023-02-08 14:54:26.965 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: org.springframework.context.event.internalEventListenerFactory

  

但是我们发现Bean1和Bean2并没有在BeanFactory中注册

BeanFactory的后置处理器只是被添加到BeanFactory,并没有调用处理方法

所以需要把每个处理器的处理方法都调用一遍才行

/* 5、获取BeanFactory处理器的容器, 用于BeanFactory的后置处理器的添加 */
Map<String, BeanFactoryPostProcessor> processorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
processorMap.values().forEach(p -> {
  /* 调用每个处理器的处理方法, 扩充Bean的定义 */
  p.postProcessBeanFactory(beanFactory);
}); log.info("在后置处理器处理后..."); /* config下的 bean1 bean2 被注册进来 */
beanDefinitionNames = beanFactory.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) log.info("beanDefinitionName: {}", beanDefinitionName);

再次打印之后发现,Bean1和Bean2加入进来了:

2023-02-08 14:54:26.972  INFO 33432 --- [           main] BeanFactoryTest                          : 在后置处理器处理后...
2023-02-08 14:54:26.972 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: config
2023-02-08 14:54:26.972 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
2023-02-08 14:54:26.972 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
2023-02-08 14:54:26.972 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: org.springframework.context.annotation.internalCommonAnnotationProcessor
2023-02-08 14:54:26.972 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: org.springframework.context.event.internalEventListenerProcessor
2023-02-08 14:54:26.972 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: org.springframework.context.event.internalEventListenerFactory
2023-02-08 14:54:26.973 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: bean1
2023-02-08 14:54:26.973 INFO 33432 --- [ main] BeanFactoryTest : beanDefinitionName: bean2

  

在Bean1中我们设置了Bean2成员属性,并且标注自动装配

然后在BeanFactory获取Bean1内的Bean2实例时,发现Bean2对象并没有注入:

/* 在没有扫描@Autowired注解驱动时不能装填Bean实例 */
log.info("打印bean2对象:{}", beanFactory.getBean(Bean1.class).getBean2());

打印结果:

2023-02-08 15:09:38.299  INFO 3852 --- [           main] BeanFactoryTest                          : 打印bean2对象:null

因为之前的处理只针对BeanFactory的后置处理,对于一个配置Bean来说

配置Bean中要注册的Bean并不归于BeanFactory的后置处理,而是Bean的后置处理

所以这里需要做Bean的后置处理:

/* 添加Bean的后置处理器 */
beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor); /* 在Bean的处理器添加之后,Bean2的对象装配了 */
log.info("打印bean2对象:{}", beanFactory.getBean(Bean1.class).getBean2());

打印结果:

2023-02-08 15:15:54.219  INFO 23160 --- [           main] BeanFactoryTest                          : 打印bean2对象:BeanFactoryTest$Bean2@2c6aed22

  

Bean不会被BeanFactory主动初始化,在首次获取这个Bean时初始化

如果需要的情况,可以调用预先实例化方法,提前创建

/* Bean对象一般在调用getBean获取时才创建, 也可以调用预先实例化方法提前创建 (只针对scope为单例的对象) */
beanFactory.preInstantiateSingletons();

  

2、自动装配的执行顺序

新增一个InterFaceType接口,Bean3和Bean4同时实现这个接口

在Bean1注册这个接口,Spring如何装配这个成员属性?

    @Data
private static class Bean1 {
@Autowired
private Bean2 bean2; // 1、指定声明bean名称
// @Autowired @Qualifier("bean4")
// private InterFaceType interFaceType; // 2、或者变量名称也可以匹配bean名称
// @Autowired
// private InterFaceType bean4; // 3、使用@Resource声明了名称,则优先级高于变量名称
// @Resource(name = "bean3")
// private InterFaceType bean4; // 4、又加 @Autowired 又加 @Resource, 交给后处理器的顺序决定先由哪个注解解析器处理
@Autowired @Qualifier("bean4")
@Resource(name = "bean3")
private InterFaceType interFaceType;
}
private static class Bean2 {} private interface InterFaceType {}
private static class Bean3 implements InterFaceType {}
private static class Bean4 implements InterFaceType {}

  

我们打印这个接口类型看看:

/*
* 可以看到默认是自动装配注解处理器先执行,所以bean4先被装填
* org.springframework.context.annotation.internalAutowiredAnnotationProcessor
* org.springframework.context.annotation.internalCommonAnnotationProcessor
*/
log.info("InterFaceType Spring实际装填对象 -> {}", beanFactory.getBean(Bean1.class).getInterFaceType());

打印结果:

2023-02-08 15:22:30.444  INFO 23516 --- [           main] BeanFactoryTest                          : InterFaceType Spring实际装填对象 -> BeanFactoryTest$Bean4@3c46dcbe

  

若要改变注解的处理顺序,就改变Bean后置处理器类的处理顺序:

/* 更改后置处理器的添加顺序 将@Resource优先被添加执行 @Autowired滞后 */
beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
.sorted(beanFactory.getDependencyComparator())
.forEach(beanFactory::addBeanPostProcessor); /*
* 默认是自动装配注解处理器先执行
* org.springframework.context.annotation.internalAutowiredAnnotationProcessor
* org.springframework.context.annotation.internalCommonAnnotationProcessor
*/
log.info("InterFaceType Spring实际装填对象 -> {}", beanFactory.getBean(Bean1.class).getInterFaceType());

打印结果:

2023-02-08 15:29:52.865  INFO 32756 --- [           main] BeanFactoryTest                          : InterFaceType Spring实际装填对象 -> BeanFactoryTest$Bean3@3c46dcbe

  

3、排序比较器对象

基于这个对象来决定处理器的先后顺序

beanFactory.getDependencyComparator()

在一开始的BeanFactory注册中就已经放置了

比较器基于处理器的顺序属性决定先后:

这里在源码可以看到两个顺序值:

我们写个测试类比较便知:

@Test
public void processorOrderCompare() {
int orderForResource = Ordered.LOWEST_PRECEDENCE - 3;
int orderForAutowired = 2147483645;
log.info("@Resource -> {}, @Autowired -> {}", orderForResource, orderForAutowired);
log.info("@Resource > @Autowired ? {}", orderForResource > orderForAutowired);
}

打印结果:

2023-02-08 15:57:31.929  INFO 17840 --- [           main] BeanFactoryTest                          : @Resource -> 2147483644, @Autowired -> 2147483645
2023-02-08 15:57:31.931 INFO 17840 --- [ main] BeanFactoryTest : @Resource > @Autowired ? false

  

三、ApplicationContextImpl的实现  

4种上下文的实现方式配置:

package cn.cloud9.spring;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.mvc.Controller; import java.net.URL; @Slf4j
public class ApplicationContextImpl { public static void main(String[] args) {
classpathXmlApplicationContext();
systemXmlApplicationContext();
annotationConfigApplicationContext();
webServletApplicationContext();
} /**
* @author OnCloud9
* @date 2023/2/8 16:30
* @description xml方式配置bean
* @params []
* @return void
*/
private static void classpathXmlApplicationContext() {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("context1.xml");
for (String beanDefinitionName : classPathXmlApplicationContext.getBeanDefinitionNames()) {
log.info("xmlRegisteredBean: {}", beanDefinitionName);
}
log.info("inside bean2 is {}", classPathXmlApplicationContext.getBean(Bean1.class).getBean2());
} /**
* @author OnCloud9
* @date 2023/2/8 16:35
* @description 文件系统方式读取xml配置bean
* @params []
* @return void
*/
private static void systemXmlApplicationContext() {
URL resource = ApplicationContextImpl.class.getClassLoader().getResource("context1.xml");
String path = resource.getPath();
FileSystemXmlApplicationContext fsXmlApplicationContext = new FileSystemXmlApplicationContext(path);
for (String beanDefinitionName : fsXmlApplicationContext.getBeanDefinitionNames()) {
log.info("systemXmlRegisteredBean: {}", beanDefinitionName);
}
log.info("inside bean2 is {}", fsXmlApplicationContext.getBean(Bean1.class).getBean2());
} /**
* @author OnCloud9
* @date 2023/2/8 16:35
* @description 当前配置类方式实现Bean配置
* @params []
* @return void
*/
private static void annotationConfigApplicationContext() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfigurationClass.class);
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
log.info("javaAnnotationBean: {}", beanDefinitionName);
}
log.info("inside bean2 is {}", applicationContext.getBean(Bean1.class).getBean2());
} /**
* @author OnCloud9
* @date 2023/2/9 09:10
* @description WebServlet应用上下文对象Bean配置
* @params []
* @return void
*/
private static void webServletApplicationContext() {
AnnotationConfigServletWebServerApplicationContext applicationContext =
new AnnotationConfigServletWebServerApplicationContext(WebMvcConfig.class);
} @Data
static class Bean1 {
private Bean2 bean2;
}
static class Bean2 {} @Configuration
static class BeanConfigurationClass {
@Bean
public Bean1 bean1(Bean2 bean2) {
Bean1 bean1 = new Bean1();
bean1.setBean2(bean2);
return bean1;
} @Bean
public Bean2 bean2() {
return new Bean2();
}
} @Configuration
static class WebMvcConfig {
/* ServletWeb服务器工厂对象配置,默认按Tomcat实现 */
@Bean
public ServletWebServerFactory servletWebServerFactory() {
return new TomcatServletWebServerFactory();
} /* 配置前置请求分发处理器 */
@Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
} /* 分发注册Bean */
@Bean
public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
} /* 直接注册一个控制器 */
@Bean("/controller1")
public Controller controller() {
return (request, response) -> {
response.getWriter().write("这是配置类的Controller!");
return null;
};
}
}
}

XML方式的配置文件(context1.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"
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 https://www.springframework.org/schema/context/spring-context.xsd"> <bean id="bean1" class="cn.cloud9.spring.ApplicationContextImpl.Bean1" >
<property name="bean2" ref="bean2" />
</bean>
<bean id="bean2" class="cn.cloud9.spring.ApplicationContextImpl.Bean2" /> <!--
后处理器的注册
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
-->
<context:annotation-config />
</beans>

  

  

【Java】Spring5学习的更多相关文章

  1. 一位资深程序员大牛推荐的Java技术学习路线图

    Web应用,最常见的研发语言是Java和PHP. 后端服务,最常见的研发语言是Java和C/C++. 大数据,最常见的研发语言是Java和Python. 可以说,Java是现阶段中国互联网公司中,覆盖 ...

  2. Java的学习之路

    记事本 EditPlus eclipse Java的学习软件,已经系统性学习Java有一段时间了,接下来我想讲一下我在Java学习用到的软件. 1.第一个软件:记事本 记事本是Java学习中最基础的编 ...

  3. Java多线程学习笔记

    进程:正在执行中的程序,其实是应用程序在内存中运行的那片空间.(只负责空间分配) 线程:进程中的一个执行单元,负责进程汇总的程序的运行,一个进程当中至少要有一个线程. 多线程:一个进程中时可以有多个线 ...

  4. Java Web 学习路线

    实际上,如果时间安排合理的话,大概需要六个月左右,有些基础好,自学能力强的朋友,甚至在四个月左右就开始找工作了.大三的时候,我萌生了放弃本专业的念头,断断续续学 Java Web 累计一年半左右,总算 ...

  5. Java基础学习-- 继承 的简单总结

    代码参考:Java基础学习小记--多态 为什么要引入继承? 还是做一个媒体库,里面可以放CD,可以放DVD.如果把CD和DVD做成两个没有联系的类的话,那么在管理这个媒体库的时候,要单独做一个添加CD ...

  6. 20145213《Java程序设计学习笔记》第六周学习总结

    20145213<Java程序设计学习笔记>第六周学习总结 说在前面的话 上篇博客中娄老师指出我因为数据结构基础薄弱,才导致对第九章内容浅尝遏止地认知.在这里我还要自我批评一下,其实我事后 ...

  7. [原创]java WEB学习笔记95:Hibernate 目录

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  8. Java多线程学习(转载)

    Java多线程学习(转载) 时间:2015-03-14 13:53:14      阅读:137413      评论:4      收藏:3      [点我收藏+] 转载 :http://blog ...

  9. java基础学习总结——java环境变量配置

    前言 学习java的第一步就要搭建java的学习环境,首先是要安装JDK,JDK安装好之后,还需要在电脑上配置"JAVA_HOME”."path”."classpath& ...

  10. Java Web学习系列——Maven Web项目中集成使用Spring、MyBatis实现对MySQL的数据访问

    本篇内容还是建立在上一篇Java Web学习系列——Maven Web项目中集成使用Spring基础之上,对之前的Maven Web项目进行升级改造,实现对MySQL的数据访问. 添加依赖Jar包 这 ...

随机推荐

  1. dubbo~全局异常拦截器的使用与设计缺陷

    异常拦截器ExceptionMapper 在JAX-RS(Java API for RESTful Web Services)中,ExceptionMapper接口用于将Java异常映射到HTTP响应 ...

  2. zabbix分布式proxy

    1.为什么要学zabbix-proxy https://www.zabbix.com/documentation/4.0/zh/manual/distributed_monitoring/proxie ...

  3. Mybatis-MySQL 中使用IFNUL

    Mybatis-MySQL 中使用IFNULL(p1,p2)函数但是有一些需要注意的地方. 假设数据 title: student id name age 1 Ann 18 2 Bom 19 3 He ...

  4. n. Elasticsearch JAVA API操作

    引言 Elasticsearch所支持的客户端连接方式有两种 Transport 连接 底层使用socket连接,用官方提供的TransPort客户端,网络IO框架使用的是netty Http连接(R ...

  5. MESI--CPU缓存一致性协议

    概念 MESI(Modified Exclusive Shared Or Invalid)(也称为伊利诺斯协议,是因为该协议由伊利诺斯州立大学提出)是一种广泛使用的支持写回策略的缓存一致性协议. ME ...

  6. RSS 解析:全球内容分发的利器及使用技巧

    使用 RSS 可以将最新的网络内容从一个网站分发到全球数千个其他网站. RSS 允许快速浏览新闻和更新. RSS 文档示例 <?xml version="1.0" encod ...

  7. 原生js或者是es中让人厌恶的一些地方

    js总体来说,是个不错的语言,最大的好处的是简单. 但这个基于es6的一些js也有一些非常怪异的写法,这是非常令人憎恶的地方. c++总体上也算不错,但为什么不是很受欢迎,因为它把自己搞得太复杂了,复 ...

  8. 忘记Linux密码这样破解

    忘记了Linux的密码该怎么办呢?有人想到重装系统.我想说除非你不想干了! 在这里使用CentOS7来教大家怎么 破解Linux的密码 (不能知道原来的密码,但是可以强行修改) 1.在grub引导界面 ...

  9. P8594 「KDOI-02」一个仇的复

    我会组合数! 首先发现同一列只有被不同的横块填或被一个相同的竖块填,且用竖块填完1列之后,会分成两个封闭的长方形,而长方形内部则用横块来填充. 先考虑一个子问题,某个 \(2 \times n\) 长 ...

  10. C#winform软件移植上linux的秘密,用GTK开发System.Windows.Forms

    国产系统大势所趋,如果你公司的winform界面软件需要在linux上运行,如果软件是用C#开发的,现在我有一个好的快速解决方案. 世界第一的微软的Microsoft Visual Studio,确实 ...