java架构之路-(spring源码篇)由浅入深-spring实战详细使用
今天我更新了一篇jvm垃圾回收的算法和垃圾回收器的内部逻辑,但是看的人不多啊......貌似大家还是比较喜欢看源码吧,毕竟实战要比理论用的多。
这篇文章不会详细的深入底层源码,只是基于注解和配置来说说我们的spring的使用,别小看基础,保证有你没用过的注解和配置,走起。
我们先来建立一个maven项目,引入spring文件,不爱弄的在文章最下面有代码地址可以去下载。先看,后面自己下载代码自己去尝试。先给你们吧,边尝试边看吧。码云地址:https://gitee.com/dwyui/springboke.git
一、IOC容器注册组件的方式
1.基础XML注入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/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="car" class="com.springIOC.bean.CarBean"></bean><!--id是唯一表示,class是全路径 -->
</beans>
package com.springIOC; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext cac = new ClassPathXmlApplicationContext("config.xml");
Object car = cac.getBean("car");
}
}
是不是超级简单的,我们由浅入深一点点来。
2.基于注解的方式来配置
package com.springIOC2.config; import com.springIOC.bean.CarBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; @Configuration
public class MainConfig {
@Bean
public CarBean car(){//注意方法名
return new CarBean();
}
}
package com.springIOC2; import com.springIOC2.config.MainConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class MainTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext aca = new AnnotationConfigApplicationContext(MainConfig.class);
Object car = aca.getBean("car");
}
}
我们通过方法名就可以直接得到我们的对象了,默认就是按照方法来装配。也可以通过@Bean(value="newName") 来指定装配的名字。
3.按照包扫描的方式装配(重点),使用@ComponentScan(basePackages={"包的全路径"})
package com.springIOC3.config; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; @Configuration
@ComponentScan(basePackages = {"com.springIOC3"})
public class MainConfig { }
package com.springIOC3; import com.springIOC3.config.MainConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class MainTest { /**
* 基础@CompentScan,包扫描方式来配置
* @param args
*/
public static void main(String[] args) {
AnnotationConfigApplicationContext aca = new AnnotationConfigApplicationContext(MainConfig.class);
String[] beanDefinitionNames = aca.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println("beanDefinitionName = " + beanDefinitionName);
}
}
}
这里在来说几个参数,excludeFilters排除某一些对象,语法如下
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class}), //排除所有Controller的注解类,多个value可以用逗号分隔
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {RepositoryBean.class}) //排除RepositoryBean类对象
}
FilterType有五种,分别是ANNOTATION(注解类),ASSIGNABLE_TYPE(类名),ASPECTJ(不常用,文档说AspectJ类型模式表达式匹配),REGEX(正则表达式匹配),CUSTOM(自定义),常用的三种我标记了红色。下面看一下具体写法
package com.springIOC3b.config; import com.springIOC3b.repository.RepositoryBean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller; @Configuration
@ComponentScan(basePackages = {"com.springIOC3b"},excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class}),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {RepositoryBean.class})
})
/**
* 1:排除用法 excludeFilters(排除@Controller注解的,和RepositoryBean类)
*/
public class MainConfig { }
刚才我们说到了自定义过滤,我们来看一下怎么写自定义的过滤,实现我们TypeFilter接口,重写我们的match即可,只关注返回的true。下面是一个事例
package com.springIOC3c.config; import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter; import java.io.IOException; public class CustomFilterType implements TypeFilter { @Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//获取当前类的注解源信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取当前类的class的源信息
ClassMetadata classMetadata = metadataReader.getClassMetadata(); //获取当前类的资源信息
Resource resource = metadataReader.getResource(); if (classMetadata.getClassName().contains("RepositoryBean")) { //这里注意,他是一个包含的匹配规则,即使我写成下面注释掉那样也可以的
return true;
}
// if (classMetadata.getClassName().contains("ryBean")) {
// return true;
// }
return false;
}
}
与包含相反的还有一个,只允许引入什么,也就是我们的includeFilters,需要注意需要把useDefaultFilters属性设置为false(true表示扫描全部的)。语法和excludeFilters完全一致
package com.springIOC3d.config; import com.springIOC3d.service.ServiceBean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller; @Configuration
@ComponentScan(basePackages = {"com.springIOC3d"},includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class}),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = ServiceBean.class)
},useDefaultFilters = false)
/**
* 只许引入*** includeFilters(只许引入@Controller注解和ServiceBean类),useDefaultFilters设置为false,关闭全包扫描
*/
public class MainConfig { }
4.回过头来,我们看一下Bean的作用域。
@Lazy懒加载,使用才实例化,看下代码,我们在Bean里加入构造方法,更方便得出什么时候实例化的。
package com.springIOC4.config; import com.springIOC4.bean.CarBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy; @Configuration
public class MainConfig {
@Bean
@Lazy
public CarBean car(){
return new CarBean();
}
}
指定@Scpoe可以有四种作用域
a) singleton 单实例的(默认),单例的生命周期有spring容器来控制,非懒加载时在spring实例化以后就产生了对象,容器销毁则对象销毁
package com.springIOC4b.config; import com.springIOC4b.bean.CarBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope; @Configuration
public class MainConfig {
@Bean
@Scope(value = "singleton")
public CarBean car(){
return new CarBean();
}
}
package com.springIOC4b; import com.springIOC4b.bean.CarBean;
import com.springIOC4b.config.MainConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class MainTest {
/**
* @Scope(value = "singleton")单例,默认也是@Scope(value = "singleton")
* @param args
*/
public static void main(String[] args) {
AnnotationConfigApplicationContext aca = new AnnotationConfigApplicationContext(MainConfig.class);
CarBean car = (CarBean)aca.getBean("car");
CarBean car2 = (CarBean)aca.getBean("car");
System.out.println(car == car2); // # true
}
}
输出结果为true,说明我们的对象是单例的,单例的对象,生命周期由spring来管理的。
b) prototype 多实例的
package com.springIOC4c.config; import com.springIOC4c.bean.CarBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope; @Configuration
public class MainConfig {
@Bean
@Scope(value = "prototype")
public CarBean car(){
return new CarBean();
}
}
package com.springIOC4c; import com.springIOC4c.bean.CarBean;
import com.springIOC4c.config.MainConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class MainTest {
/**
* @Scope(value = "prototype")多例
* @param args
*/
public static void main(String[] args) {
AnnotationConfigApplicationContext aca = new AnnotationConfigApplicationContext(MainConfig.class);
CarBean car = (CarBean)aca.getBean("car");
CarBean car2 = (CarBean)aca.getBean("car");
System.out.println(car == car2); // # false
}
}
多例的不受ioc容器来管理,销毁时是由GC来清理的,还有request同一次请求和session同一个会话级别的,这里就不一一演示了。
5.@Configuration注解,来判断是否注入Bean的。
package com.springIOC5.config; import com.springIOC5.bean.CarBean;
import com.springIOC5.bean.UserBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration; @Configuration
public class MainConfig { @Bean(value = "user")
public UserBean userBean() {
return new UserBean();
} @Bean
@Conditional(value = IOCConditional.class)
public CarBean carBean() {
return new CarBean();
}
}
package com.springIOC5.config; import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata; public class IOCConditional implements Condition { @Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
if (context.getBeanFactory().containsBean("user")) { //这里必须和Bean的名称完全一致。
return true;
}
return false;
}
}
上面的代码什么意思呢?就是我们是否需要注入carBean,如果包含user这个对象,就注入我们的carBean,不包含就不注入,这里有个意思的事,Configuration配置里类的注入是有顺序的,我们必须把我们作为判断条件的Bean放在上面,否则Conditional会识别你没有那个判断条件的Bean。
6.@Import引入方式注入Bean
package com.springIOC6.config; import com.springIOC6.bean.CarBean;
import com.springIOC6.bean.UserBean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; @Configuration
@Import({CarBean.class, UserBean.class})
public class MainConfig { }
直接在注解内写入我们的要注入的类即可,也可以使用接口的方式来实现,我们来看换一下。
package com.springIOC6b.config; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; @Configuration
@Import({ImportSelector.class})
public class MainConfig { }
package com.springIOC6b.config; import org.springframework.core.type.AnnotationMetadata; public class ImportSelector implements org.springframework.context.annotation.ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.springIOC6b.bean.CarBean","com.springIOC6b.bean.UserBean"};
}
}
实现ImportSelector类,然后返回类名全路径即可。自动装配就是基于@Import实现的。
实现ImportBeanDefinitionRegistrar,重写registerBeanDefinitions方法,也是可以的。
package com.springIOC6c.config; import com.springIOC6c.bean.CarBean;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata; public class ImportSelectorRegister implements ImportBeanDefinitionRegistrar { @Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(CarBean.class);
registry.registerBeanDefinition("CarBean",rootBeanDefinition);
}
}
7.通过FactoryBean注入
package com.springIOC7.config; import com.springIOC7.bean.UserBean;
import org.springframework.beans.factory.FactoryBean; public class IOCFactoryBean implements FactoryBean<UserBean> { @Override
public UserBean getObject() throws Exception {//指定对象
return new UserBean();
} @Override
public Class<?> getObjectType() {//指定类型
return UserBean.class;
} @Override
public boolean isSingleton() {//指定是否为单例
return true;
}
}
package com.springIOC7.config; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; @Configuration
public class MainConfig {
@Bean
public IOCFactoryBean iocFactoryBean(){
return new IOCFactoryBean();
}
}
package com.springIOC7; import com.springIOC7.config.MainConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class MainTest { /**
* FactoryBean注入
* @param args
*/
public static void main(String[] args) {
AnnotationConfigApplicationContext aca = new AnnotationConfigApplicationContext(MainConfig.class);
Object carBean = aca.getBean("iocFactoryBean");//取出userBean
System.out.println(carBean); Object iocFactoryBean = aca.getBean("&iocFactoryBean");//取得FactoryBean
System.out.println(iocFactoryBean);
}
}
说到这所有往IOC容器中添加组件的方式就全部说完了,简单总结一下:
@Bean注入,可以指定四种作用域,单例,多例(生命周期不受IOC容器管理),一次请求和一次会话,也可以设置懒加载,
@ComponentScan指定包扫描的方式来注入,配合@Controller,@Repository,@Service,@Component注解来使用。
@Import方式注入,两种实现类ImportSelector和ImportBeanDefinitionRegistrar两种方式。
@FactoryBean,工程Bean的方式也可以注入。注意不带&是取得最终对象,带&是取得真实Bean。三个方法,一个指定对象,一个指定类型,一个指定是否为单例。
二、Bean的生命周期---初始化方法和销毁方法
针对单实例bean的话,容器启动的时候,bean的对象就创建了,而且容器销毁的时候,也会调用Bean的销毁方法。
针对多实例bean的话,容器启动的时候,bean是不会被创建的而是在获取bean的时候被创建,而且bean的销毁不受IOC容器的管理。
1.我们先来看个最简单的方法,用initMethod和destroyMethod来指定我们的初始化方法和销毁方法
package com.springlifeCycle1a.config; import com.springlifeCycle1a.bean.CarBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; @Configuration
public class MainConfig { @Bean(initMethod = "init",destroyMethod = "destroy")
public CarBean car() {
return new CarBean();
}
}
我们在指定了我们的init初始方法,销毁方法为destroy方法。调用顺序是,Car的构造方法,Car的init方法,Car的destroy方法,也可以自己尝试使用@Lazy注解。码云代码里有可以自己去尝试。
2.通过 InitializingBean和DisposableBean 的两个接口实现bean的初始化以及销毁方法
package com.springlifeCycle2a.bean; import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean; public class CarBean implements InitializingBean, DisposableBean {
public CarBean() {
System.out.println("我是Car");
} public void afterPropertiesSet() {
System.out.println("我是初始化init");
} public void destroy() {
System.out.println("我是销毁destroy");
}
}
3.通过JSR250规范 提供的注解@PostConstruct 和@ProDestory标注的方法
package com.springlifeCycle3.bean; import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy; public class CarBean {
public CarBean() {
System.out.println("我是Car");
} @PostConstruct
public void init() {
System.out.println("我是初始化init--PostConstruct");
} @PreDestroy
public void destory() {
System.out.println("我是销毁destroy--PreDestroy");
} }
4.通过Spring的BeanPostProcessor的 bean的后置处理器会拦截所有bean创建过程 (这个方法后面讲源码的时候会去讲内部实现,自己觉得有必要看这个的源码)
package com.springlifeCycle4.bean; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component; @Component
public class LifeBeanPostProcessor implements BeanPostProcessor { @Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化方法" + beanName);
return bean;
} @Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("销毁方法" + beanName);
return bean;
}
}
这里也总结一下,我们来指定容器内对象的初始化方法和销毁方法的方式一共有四种
1.用@Bean的initMethod 和destroyMethod 来给予初始化方法和销毁方法。
2.通过 InitializingBean和DisposableBean 的二个接口实现bean的初始化以及销毁方法。
3.通过JSR250规范 提供的注解@PostConstruct 和@ProDestory标注的方法。
4.通过Spring的BeanPostProcessor的 bean的后置处理器会拦截所有bean创建过程。
三、给属性赋值
这里的东西不多,我就尽快说一下啦,赋值的方式有三种我们来看一下。
package com.springValue.config; import com.springValue.bean.CarBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource; @Configuration
@PropertySource(value = "classpath:carBean.properties",encoding = "utf-8") //指定外部文件的位置
public class MainConfig { @Bean
public CarBean carBean() {
return new CarBean();
}
}
import org.springframework.beans.factory.annotation.Value; public class CarBean { @Value("宝马")//通过普通的方式
private String name; @Value("#{5-2}")//spel方式来赋值
private int carNum; @Value("${carBean.realName}")//通过读取外部配置文件的值
private String realName; }//自己记得加get set方法。
这里值得一提的就是导入文件最好设置一下encoding = "utf-8",不然汉字会乱码。
四、自动装配:
主动装配平时是我们最熟悉的,用的也是最多的,我们来复习一下。
1.@Autowired 自动装配首先时按照类型进行装配,若在IOC容器中发现了多个相同类型的组件,那么就按照 属性名称来进行装配
package com.springxAutowired1.config; import com.springxAutowired1.dao.AutowiredDao;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; @Configuration
@ComponentScan(value = "com.springxAutowired1.service")
public class MainConfig { @Bean
public AutowiredDao autowiredDao1(){
return new AutowiredDao(1);
} @Bean
public AutowiredDao autowiredDao2(){
return new AutowiredDao(2);
}
}
package com.springxAutowired1.service; import com.springxAutowired1.dao.AutowiredDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; @Service
public class ServiceBean { @Autowired
private AutowiredDao autowiredDao2; public ServiceBean() {
System.out.println("我是serviceBean");
} @Override
public String toString() {
return "ServiceBean{" +
"AutowiredDao=" + autowiredDao2 +
'}';
}
}
在这里我们设置了两个AutowiredDao的对象,一个标识为1,一个标识为2,ServiceBean默认是按照名字来装配的。
2.我们也可以通过@Qualifier来指定装配名字。
package com.springxAutowired1b.service; import com.springxAutowired1b.dao.AutowiredDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service; @Service
public class ServiceBean { @Autowired
@Qualifier(value = "autowiredDao1")
private AutowiredDao autowiredDao2; public ServiceBean() {
System.out.println("我是serviceBean");
} @Override
public String toString() {
return "ServiceBean{" +
"AutowiredDao=" + autowiredDao2 +
'}';
}
}
3.我们使用Qualifier是如果名字写错了,可能装配错误会报错,这时我们可以使用required = false来阻止异常的抛出
package com.springxAutowired3.service; import com.springxAutowired3.dao.AutowiredDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service; @Service
public class ServiceBean { @Qualifier(value = "autowiredDaoError")
@Autowired(required = false)
private AutowiredDao autowiredDao2; public ServiceBean() {
System.out.println("我是serviceBean");
} @Override
public String toString() {
return "ServiceBean{" +
"AutowiredDao=" + autowiredDao2 +
'}';
}
}
注意:这里我并没有说@Resource注解,这个注解其实不是spring里的,是JSR250规范的,但是不支持@Primary 和@Qualifier的支持
五、环境切换:
我们有时候需要通过不同的环境来切换我们的配置,我们通过@Profile注解,来根据环境来激活标识不同的Bean,
@Profile标识在类上,那么只有当前环境匹配,整个配置类才会生效
@Profile标识在Bean上 ,那么只有当前环境的Bean才会被激活
package com.springxAutowired4.config; import com.springxAutowired4.bean.Environment;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile; @Configuration
public class MainConfig { @Bean
@Profile(value = "test")
public Environment environment_test() {
return new Environment("test");
} @Bean
@Profile(value = "dev")
public Environment environment_dev() {
return new Environment("dev");
} @Bean
@Profile(value = "pro")
public Environment environment_pro() {
return new Environment("pro");
}
}
激活切换环境的方法
方法一:通过运行时jvm参数来切换 -Dspring.profiles.active=test,dev,prod多个参数表中间使用英文的逗号来分隔
方法二:通过代码的方式来激活
package com.springxAutowired4; import com.springxAutowired4.config.MainConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class MainTest { /**
* 环境切换
* @param args
*/
public static void main(String[] args) {
AnnotationConfigApplicationContext aca = new AnnotationConfigApplicationContext();
aca.getEnvironment().setActiveProfiles("test","dev");//方便演示,我写了两个,一般都是一个的. aca.register(MainConfig.class);
aca.refresh();
for (String beanDefinitionName : aca.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
}
}
如果两个都写了,按照代码中的来实现,参数不再起作用
今天就说到这里, 大概就这么多吧。后期我也会基于这篇博客来详细的扒一下源码,中间会穿插一些spring的常见面试题。
代码地址:https://gitee.com/dwyui/springboke.git
最进弄了一个公众号,小菜技术,欢迎大家的加入
java架构之路-(spring源码篇)由浅入深-spring实战详细使用的更多相关文章
- java架构之路-(源码)mybatis基本使用
我们今天先来简单了解一下我们持久层框架,mybatis的使用.而且现在的注解成为趋势,我主要说一下注解方向的使用吧(配置文件也会说) 从使用角度只要是三个部分,mybatis-config.xml,m ...
- java架构之路-(源码)mybatis的一二级缓存问题
上次博客我们说了mybatis的基本使用,我们还捎带提到一下Mapper.xml中的select标签的useCache属性,这个就是设置是否存入二级缓存的. 回到我们正题,经常使用mybatis的小伙 ...
- java架构之路-(源码)mybatis执行流程源码解析
这次我们来说说Mybatis的源码,这里只说执行的流程,内部细节太多了,这里只能授之以渔了.还是最近的那段代码,我们来回顾一下. package mybatis; import mybatis.bea ...
- Spring源码-IOC部分-Spring是如何解决Bean循环依赖的【6】
实验环境:spring-framework-5.0.2.jdk8.gradle4.3.1 Spring源码-IOC部分-容器简介[1] Spring源码-IOC部分-容器初始化过程[2] Spring ...
- Spring源码-AOP部分-Spring是如何对bean实现AOP代理的
实验环境:spring-framework-5.0.2.jdk8.gradle4.3.1 历史文章 Spring源码-IOC部分-容器简介[1] Spring源码-IOC部分-容器初始化过程[2] S ...
- java架构之路-(spring源码篇)springIOC容器源码解析(上)
我们这次来叭叭一下Spring的源码,这次博客主要来说说Spring源码,先粗略的撸一遍,下篇博客选几个重点去说,由于过于复杂,我也是看了一点点,我们先来过一遍源码,然后上流程图,最后我们再回头总结一 ...
- spring源码深度解析—Spring的整体架构和环境搭建
概述 Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用.Spring是于2003 年兴起的一个轻量级的Java 开发框 ...
- 框架源码系列六:Spring源码学习之Spring IOC源码学习
Spring 源码学习过程: 一.搞明白IOC能做什么,是怎么做的 1. 搞明白IOC能做什么? IOC是用为用户创建.管理实例对象的.用户需要实例对象时只需要向IOC容器获取就行了,不用自己去创建 ...
- spring源码学习(三)--spring循环引用源码学习
在spring中,是支持单实例bean的循环引用(循环依赖)的,循环依赖,简单而言,就是A类中注入了B类,B类中注入了A类,首先贴出我的代码示例 @Component public class Add ...
随机推荐
- abp(net core)+easyui+efcore实现仓储管理系统——使用 WEBAPI实现CURD (十四)
abp(net core)+easyui+efcore实现仓储管理系统目录 abp(net core)+easyui+efcore实现仓储管理系统——ABP总体介绍(一) abp(net core)+ ...
- Java并发之内存模型(JMM)浅析
背景 学习Java并发编程,JMM是绕不过的槛.在Java规范里面指出了JMM是一个比较开拓性的尝试,是一种试图定义一个一致的.跨平台的内存模型.JMM的最初目的,就是为了能够支多线程程序设计的,每个 ...
- Code signing is required for product type 'Unit Test Bundle' in SDK 'iOS 11.0.1'
Code signing is required for product type 'Unit Test Bundle' in SDK 'iOS 11.0.1' 进入 projects and lis ...
- 消息中间件——RabbitMQ(七)高级特性全在这里!(上)
前言 前面我们介绍了RabbitMQ的安装.各大消息中间件的对比.AMQP核心概念.管控台的使用.快速入门RabbitMQ.本章将介绍RabbitMQ的高级特性.分两篇(上/下)进行介绍. 消息如何保 ...
- net core WebApi——文件分片下载
目录 前言 开始 测试 小结 @ 前言 上一篇net core WebApi--文件分片上传与跨域请求处理介绍完文件的上传操作,本来是打算紧接着写文件下载,中间让形形色色的事给耽误的,今天还是抽个空整 ...
- 《HelloGitHub》第 41 期
兴趣是最好的老师,HelloGitHub 就是帮你找到兴趣! 简介 分享 GitHub 上有趣.入门级的开源项目. 这是一个面向编程新手.热爱编程.对开源社区感兴趣 人群的月刊,月刊的内容包括:各种编 ...
- Visual Studio 2019 远程调试工具(Remote Debugger)使用方法
目录 0.Visual Studio 2019 远程调试工具使用场景 1.Visual Studio 2019 远程调试工具下载地址: 2.Visual Studio 2019 远程调试工具-安装及运 ...
- 计算机基础+python初阶
今日内容: 1.计算机基础知识 2.python简介 3.快速入门 今日内容: 一.计算机基础 1. 计算机什么组成的 输入输出设备 cpu 硬盘 内存 中央处理器 处理各种数据 相当于人的大脑 内存 ...
- Redis设计原理
1.简介 Redis中的每个Key-Value在内存中都会被划分成DictEntry.RedisObject以及具体对象,其中DictEntry又分别包含指向Key和Value的指针(以RedisOb ...
- 特殊字符处理 java-jsp
public String dealStr(String name){ String newStr=""; if(name != null && name.leng ...