代码地址:https://github.com/showkawa/spring-annotation/tree/master/src/main/java/com/brian

1.源码分析二主要分析的内容

1.使用@Condition多条件注册bean对象
2.@Import注解快速注入第三方bean对象
3.@EnableXXXX 开启原理
4.基于ImportBeanDefinitionRegistrar注册bean
5.基于FactoryBean注册bean对象

1.使用@Conditional多条件注册bean对象

conditional字面意思条件句,亦即满足某些条件将该类注册到IOC容器的意思

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional { /**
* All {@link Condition Conditions} that must {@linkplain Condition#matches match}
* in order for the component to be registered.
*/
Class<? extends Condition>[] value(); }

可以看到 Conditional注解的value是Condition的子类或实现类

我这里写自定义的BriancCondition类来实现Condition接口,可以看到Condition就一个返回boolean值的mathes()方法

public class BrianCondition implements Condition {

    /*
* context:判断条件能使用的上下文(环境)
* metadata: 注释信息
* */
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { System.out.println("---male:" + context.getRegistry().containsBeanDefinition("person"));
     //我这里判断ioc容器中是否有person实例,有返回true,否则返回false
if(context.getRegistry().containsBeanDefinition("person"))
return true; return false;
}
}

现在在配置类中加上,注册Person类到容器中,然后用@Conditional控制是否将person01和person02注册到容器中

@Configuration //告诉spring这是一个配置类
/*
* @ComponentScan
* value:只当于扫描的的包
* excludeFilters = 指定扫描的时候按照什么规则排除哪些组件
* includeFilters = 指定扫描的时候只需要包含哪些组件
* Filter.ANNOTATION:按照注解
* Filter.ASSIGNABLE_TYPE: 按照给定的类型
* */ @ComponentScans(value = {
@ComponentScan(value = "com.brian",includeFilters = {
// @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class}),
// @ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE,classes = {BookService.class}),
@ComponentScan.Filter(type = FilterType.CUSTOM,classes = {BrianTypeFilter.class})
},useDefaultFilters = false)
})
//@Import({Brian.class,Alan.class,BrianSelector.class})
public class MainConfig { @Bean("person") //给容器中注册一个Bean;类型为返回值的类型;id默认是方法名作为id
public Person person(){
return new Person("Alan",18);
} /*
* @Conditional() 按照条件注册
*
* */
@Conditional({BrianCondition.class})
@Bean("person01")
public Person person01() {
return new Person("Brian",17);
} @Conditional({BrianCondition.class})
@Bean("person02")
public Person person02() {
return new Person("wenTao",19);
} /*
*
*给容器中注册组件
* 1,包扫描+ 组件标注注解(@Controller/@Service/@Repository/@Component)[自己写的方法]
* 2, @Bean [导入的第三方包里面的组件]
* 3,@Import [快速的给容器导入一个组件]
* 1.@Import(要导入的组件class)
* 2.ImportSelector:返回需要导入的组件的全类名数组
* 3.ImportBeanDefinitionRegistrar: 手动注册bean到容器
* 4. 使用Spring提供的FactoryBean
* */
@Bean
public BrianBeanFactory brianBeanFactory() {
return new BrianBeanFactory();
} }

加上测试类

public class MainTest {
public static void main(String[] args) {
ApplicationContext acac =
new AnnotationConfigApplicationContext(MainConfig.class);
/* ApplicationContext acac =
new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);*/
System.out.println("ioc容器创建成功");
// Alan alan1 = acac.getBean(Alan.class);
// Alan alan2 = acac.getBean(Alan.class);
//System.out.println("比较两个Alan实例: " + (alan1 == alan2));
Person person1 = (Person) acac.getBean("person01");
System.out.println("---main---test---person1---: " + person1.toString());
Person person2 = (Person) acac.getBean("person02");
System.out.println("---main---test---person2---: " + person2.toString()); //关闭ioc容器
((AnnotationConfigApplicationContext) acac).close();
}
}

你会发现控制台可以获取到对象person01和person02的信息

我这边再做一个matches发返回false的测试,亦即修改BrianCondition类的matches返回值为false,可以下面的测试结果:NoSuchBeanDefinitionException: No bean named 'person01' available。所i以根据上面我们测试的接口可以知道@Conditional注解的使用也是简单的

2.@Import注解快速注入第三方bean对象

通过@Import可以快速的导入依赖的bean对象,比如我们在配置类上导入其他类@Import({Brian.class,Alan.class})

configure配置类

@Configuration //告诉spring这是一个配置类
/*
* @ComponentScan
* value:只当于扫描的的包
* excludeFilters = 指定扫描的时候按照什么规则排除哪些组件
* includeFilters = 指定扫描的时候只需要包含哪些组件
* Filter.ANNOTATION:按照注解
* Filter.ASSIGNABLE_TYPE: 按照给定的类型
* */ @ComponentScans(value = {
@ComponentScan(value = "com.brian",includeFilters = {
// @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class}),
// @ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE,classes = {BookService.class}),
@ComponentScan.Filter(type = FilterType.CUSTOM,classes = {BrianTypeFilter.class})
},useDefaultFilters = false)
})
@Import({Brian.class,Alan.class})
//@Import({BrianSelector.class})
public class MainConfig { @Bean("person") //给容器中注册一个Bean;类型为返回值的类型;id默认是方法名作为id
public Person person(){
return new Person("Alan",18);
} /*
* @Conditional() 按照条件注册
*
* */
@Conditional({BrianCondition.class})
@Bean("person01")
public Person person01() {
return new Person("Brian",17);
} @Conditional({BrianCondition.class})
@Bean("person02")
public Person person02() {
return new Person("wenTao",19);
} /*
*
*给容器中注册组件
* 1,包扫描+ 组件标注注解(@Controller/@Service/@Repository/@Component)[自己写的方法]
* 2, @Bean [导入的第三方包里面的组件]
* 3,@Import [快速的给容器导入一个组件]
* 1.@Import(要导入的组件class)
* 2.ImportSelector:返回需要导入的组件的全类名数组
* 3.ImportBeanDefinitionRegistrar: 手动注册bean到容器
* 4. 使用Spring提供的FactoryBean
* */
@Bean
public BrianBeanFactory brianBeanFactory() {
return new BrianBeanFactory();
} }

测试类


public class MainTest {
public static void main(String[] args) {
ApplicationContext acac =
new AnnotationConfigApplicationContext(MainConfig.class); /* ApplicationContext acac =
new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);*/
System.out.println("ioc容器创建成功");
Alan alan1 = acac.getBean(Alan.class);
System.out.println("--ALAN--:" + alan1);
// Alan alan2 = acac.getBean(Alan.class);
//System.out.println("比较两个Alan实例: " + (alan1 == alan2)); // Person person1 = (Person) acac.getBean("person01");
// System.out.println("---main---test---person1---: " + person1.toString());
// Person person2 = (Person) acac.getBean("person02");
// System.out.println("---main---test---person2---: " + person2.toString()); // MathCalculator mathCalculator = (MathCalculator) acac.getBean("mathCalculator");
// System.out.println("----get--mathCalculator---: " + mathCalculator); //关闭ioc容器
((AnnotationConfigApplicationContext) acac).close();
}
}
 

@Import上面的使用方式属于静态的导入依赖,当然Import注解还有一种动态导入第三组件的方式是和ImportSelector结合使用

比如我在这里MainConfig配置类上通过Import注解导入BrianSelector类.

@Configuration //告诉spring这是一个配置类
/*
* @ComponentScan
* value:只当于扫描的的包
* excludeFilters = 指定扫描的时候按照什么规则排除哪些组件
* includeFilters = 指定扫描的时候只需要包含哪些组件
* Filter.ANNOTATION:按照注解
* Filter.ASSIGNABLE_TYPE: 按照给定的类型
* */ @ComponentScans(value = {
@ComponentScan(value = "com.brian",includeFilters = {
// @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class}),
// @ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE,classes = {BookService.class}),
@ComponentScan.Filter(type = FilterType.CUSTOM,classes = {BrianTypeFilter.class})
},useDefaultFilters = false)
})
//@Import({Brian.class,Alan.class})
@Import({BrianSelector.class})
public class MainConfig { @Bean("person") //给容器中注册一个Bean;类型为返回值的类型;id默认是方法名作为id
public Person person(){
return new Person("Alan",18);
} /*
* @Conditional() 按照条件注册
*
* */
@Conditional({BrianCondition.class})
@Bean("person01")
public Person person01() {
return new Person("Brian",17);
} @Conditional({BrianCondition.class})
@Bean("person02")
public Person person02() {
return new Person("wenTao",19);
} /*
*
*给容器中注册组件
* 1,包扫描+ 组件标注注解(@Controller/@Service/@Repository/@Component)[自己写的方法]
* 2, @Bean [导入的第三方包里面的组件]
* 3,@Import [快速的给容器导入一个组件]
* 1.@Import(要导入的组件class)
* 2.ImportSelector:返回需要导入的组件的全类名数组
* 3.ImportBeanDefinitionRegistrar: 手动注册bean到容器
* 4. 使用Spring提供的FactoryBean
* */
@Bean
public BrianBeanFactory brianBeanFactory() {
return new BrianBeanFactory();
} }

BrianSelector类,该类实现了ImportSelector接口,通过实现selectImports方法,返回需要动态导入到IOC容器的其他的配置类的全量类名

/*
* 自定义返回需要导入的组件
* */
public class BrianSelector implements ImportSelector { /**
*
* @param importingClassMetadata 当前被标记有@Import注解的所有注解信息
* @return
*/
public String[] selectImports(AnnotationMetadata importingClassMetadata) { System.out.println("----ImportSelector----:"+importingClassMetadata.getClassName());
//return new String[]{};
return new String[]{MainConfigOfAOP.class.getName()};
}
}

MainConfigOfAOP配置类有注入MathCalculator对象

@Configuration
ublic class MainConfigOfAOP { @Bean
public MathCalculator mathCalculator()
{
return new MathCalculator();
} }

测试类,主要测试在IOC容器中获取MathCalculator类的信息

public class MainTest {
public static void main(String[] args) {
ApplicationContext acac =
new AnnotationConfigApplicationContext(MainConfig.class); /* ApplicationContext acac =
new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);*/
System.out.println("ioc容器创建成功");
// Alan alan1 = acac.getBean(Alan.class);
// System.out.println("--ALAN--:" + alan1);
// Alan alan2 = acac.getBean(Alan.class);
//System.out.println("比较两个Alan实例: " + (alan1 == alan2)); // Person person1 = (Person) acac.getBean("person01");
// System.out.println("---main---test---person1---: " + person1.toString());
// Person person2 = (Person) acac.getBean("person02");
// System.out.println("---main---test---person2---: " + person2.toString()); MathCalculator mathCalculator = (MathCalculator) acac.getBean("mathCalculator");
System.out.println("----get--mathCalculator---: " + mathCalculator); //关闭ioc容器
((AnnotationConfigApplicationContext) acac).close();
}
}

这里简单的扩展下@Import注解和@Bean注解异同点
1.都是导入的外部的Jar包
2.@Import的bean id是当前完整路径地址注册到IOC容器,@Bean的bean id是以方法名注册到IOC容器,相比来说@Import注入类更加简单

3.@EnableXXXX 开启原理

enable字面意思启动,亦即开关的概念,有@EnableXXXX注解的地方,基本会看到@Import这个注解,一般他们都是结合起来使用的

比如看到我代码里面的MainConfigOfAutowired这个配置类,上有加上@EnableTransactionManagement这个注解,亦即打开事务管理

/**
* 自动装配
* Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值
*1).@Autowired,自动注入:
* 1.默认优先按照类型去容器中找对应的组件:applicationContext.getBean(BookDao.class);
* 2.如果找到多个相同类型的组件,再将属性方法的名称作为组件的id去容器中查找
* applicationContext.getBean("bookDao");
* 3.@Qualifier("bookDao"):使用@Qualifier指定需要装配的组件id,而不是使用属性名
* 4.自动装配默认一定要将属性赋值好,没有就会报错
* 使用@Autoeired(required=false),没有默认值也不会报错
* 5.@Primary, 让Spring进行自动装配的时候,默认使用首先的Bean
*
* 2).Spring还支持使用@Resource(JSR250)和@Inject(JSR330) [java规范的注解]
* 3).@Autowired :构造器,参数,方法,属性,
*
*/
@EnableAspectJAutoProxy //开启AOP代理自动配置
@EnableTransactionManagement //基于注解的事务管理
//@ComponentScan(value = {"com.brian.bean","com.write.annotation"})
@ComponentScan(value = {"com.write.annotation.transaction"})
@Configuration
public class MainConfigOfAutowired { @Bean
public DataSource dataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setJdbcUrl("jdbc:mysql://remotemysql.com:3306/khgvUiO4eh");

我们再看看@EnableTransactionManagement的代码,通过Import快速导入TransactionManagementConfigurationSelector

@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement { /**
* Indicate whether subclass-based (CGLIB) proxies are to be created ({@code true}) as
* opposed to standard Java interface-based proxies ({@code false}). The default is
* {@code false}. <strong>Applicable only if {@link #mode()} is set to
* {@link AdviceMode#PROXY}</strong>.
* <p>Note that setting this attribute to {@code true} will affect <em>all</em>
* Spring-managed beans requiring proxying, not just those marked with
* {@code @Transactional}. For example, other beans marked with Spring's
* {@code @Async} annotation will be upgraded to subclass proxying at the same
* time. This approach has no negative impact in practice unless one is explicitly
* expecting one type of proxy vs another, e.g. in tests.
*/
boolean proxyTargetClass() default false; /**
* Indicate how transactional advice should be applied.
* <p><b>The default is {@link AdviceMode#PROXY}.</b>
* Please note that proxy mode allows for interception of calls through the proxy
* only. Local calls within the same class cannot get intercepted that way; an
* {@link Transactional} annotation on such a method within a local call will be
* ignored since Spring's interceptor does not even kick in for such a runtime
* scenario. For a more advanced mode of interception, consider switching this to
* {@link AdviceMode#ASPECTJ}.
*/
AdviceMode mode() default AdviceMode.PROXY; /**
* Indicate the ordering of the execution of the transaction advisor
* when multiple advices are applied at a specific joinpoint.
* <p>The default is {@link Ordered#LOWEST_PRECEDENCE}.
*/
int order() default Ordered.LOWEST_PRECEDENCE; }

我们再点进去看看TransactionManagementConfigurationSelector这个类,会发现selectImports会根据条件,选择不同的配置类,所以这就是为什么说ImportSelector可以动态加载其他配置类了

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

    /**
* Returns {@link ProxyTransactionManagementConfiguration} or
* {@code AspectJ(Jta)TransactionManagementConfiguration} for {@code PROXY}
* and {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()},
* respectively.
*/
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
} private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
} }

4.基于ImportBeanDefinitionRegistrar注册bean

再回到MainConfigOfAOP这个配置类

/**
* AOP: [动态代理]
* 指在程序运行时期间将某段代码切入到指定方法指定位置执行的编程方式
*
* 1.将业务逻辑类和切面类注入到容器中(加上@Aspect注解表示切面类 )
* 2.在切面类上的每个通知方法注解上注解,定义好切点
* 3.开启基于注解的AOP模式: @EnableAspectAutoProxy
*
*
* AOP 原理:
* @EnableAspectJAutoProxy
* @Import(AspectJAutoProxyRegistrar.class) 给容器中导入AspectJAutoProxyRegistrar类
* 利用AspectJAutoProxyRegistrar自定义向容器中注册bean
* AnnotationAwareAspectJAutoProxyCreator
* ->AspectJAwareAdvisorAutoProxyCreator
* ->AbstractAdvisorAutoProxyCreator
* ->AbstractAutoProxyCreator
* implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
* 后置处理器(在bean初始化完成前后执行) ,自动装配BeanFactory
*
*
*
*/
@Configuration
@EnableAspectJAutoProxy
public class MainConfigOfAOP { @Bean
public MathCalculator mathCalculator()
{
return new MathCalculator();
} @Bean
public LogAspects logAspects() {
return new LogAspects();
}
}

上面通过@EnableAspectJAutoProxy开启基于注解的AOP模式,我们点进去看看,又是熟悉的@Import注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy { /**
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}.
*/
boolean proxyTargetClass() default false; /**
* Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
* for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
* Off by default, i.e. no guarantees that {@code AopContext} access will work.
* @since 4.3.1
*/
boolean exposeProxy() default false; }

我们再点进去看看AspectJAutoProxyRegistrar这个类

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

    /**
* Register, escalate, and configure the AspectJ auto proxy creator based on the value
* of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
* {@code @Configuration} class.
*/
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
} }

你会发现该类通过实现ImportBeanDefinitionRegistrar接口的registerBeanDefinitions的方法,最终通过AopConfigUtil工具类来注册到容器中

5.基于FactoryBean注册bean对象

再次回到我的MainConfig这个配置类

@Configuration //告诉spring这是一个配置类
/*
* @ComponentScan
* value:只当于扫描的的包
* excludeFilters = 指定扫描的时候按照什么规则排除哪些组件
* includeFilters = 指定扫描的时候只需要包含哪些组件
* Filter.ANNOTATION:按照注解
* Filter.ASSIGNABLE_TYPE: 按照给定的类型
* */ @ComponentScans(value = {
@ComponentScan(value = "com.brian",includeFilters = {
// @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class}),
// @ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE,classes = {BookService.class}),
@ComponentScan.Filter(type = FilterType.CUSTOM,classes = {BrianTypeFilter.class})
},useDefaultFilters = false)
})
//@Import({Brian.class,Alan.class})
@Import({BrianSelector.class})
public class MainConfig { @Bean("person") //给容器中注册一个Bean;类型为返回值的类型;id默认是方法名作为id
public Person person(){
return new Person("Alan",18);
} /*
* @Conditional() 按照条件注册
*
* */
@Conditional({BrianCondition.class})
@Bean("person01")
public Person person01() {
return new Person("Brian",17);
} @Conditional({BrianCondition.class})
@Bean("person02")
public Person person02() {
return new Person("wenTao",19);
} /*
*
*给容器中注册组件
* 1,包扫描+ 组件标注注解(@Controller/@Service/@Repository/@Component)[自己写的方法]
* 2, @Bean [导入的第三方包里面的组件]
* 3,@Import [快速的给容器导入一个组件]
* 1.@Import(要导入的组件class)
* 2.ImportSelector:返回需要导入的组件的全类名数组
* 3.ImportBeanDefinitionRegistrar: 手动注册bean到容器
* 4. 使用Spring提供的FactoryBean
* */
@Bean
public BrianBeanFactory brianBeanFactory() {
return new BrianBeanFactory();
} }

通过@Bean注解注入BrianBeanFactory,我们点进去看看

public class BrianBeanFactory  implements FactoryBean<WenTao> {
//获取对象
public WenTao getObject() throws Exception {
return new WenTao();
}
//获取对象的类型
public Class<?> getObjectType() {
return WenTao.class;
} //获取对象是单例模式还是原型模式
public boolean isSingleton() {
return true;
}
}

BrianBeanFactoryt通过实现了BeanFactory接口的getObject()获取到bean对象

上测试类

public class MainTest {
public static void main(String[] args) {
ApplicationContext acac =
new AnnotationConfigApplicationContext(MainConfig.class); /* ApplicationContext acac =
new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);*/
System.out.println("ioc容器创建成功");
// Alan alan1 = acac.getBean(Alan.class);
// System.out.println("--ALAN--:" + alan1);
// Alan alan2 = acac.getBean(Alan.class);
//System.out.println("比较两个Alan实例: " + (alan1 == alan2)); // Person person1 = (Person) acac.getBean("person01");
// System.out.println("---main---test---person1---: " + person1.toString());
// Person person2 = (Person) acac.getBean("person02");
// System.out.println("---main---test---person2---: " + person2.toString()); // MathCalculator mathCalculator = (MathCalculator) acac.getBean("mathCalculator");
// System.out.println("----get--mathCalculator---: " + mathCalculator); BrianBeanFactory beanFactory = acac.getBean(BrianBeanFactory.class);
WenTao wentao = null;
try {
wentao = beanFactory.getObject();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("----get--WenTao---: " + wentao); //关闭ioc容器
((AnnotationConfigApplicationContext) acac).close();
}
}

这里拓展一点FactoryBean和 BeanFactory的区别,FactoryBean是创建bean对象,BeanFactory是获取bean对象。

最后说一下,我的博客可能不是首创,但也属于我自己根据自己理解一点点分析的,如果有帮助到你,转载请注明出处!

Spring5源码深度分析(二)之理解@Conditional,@Import注解的更多相关文章

  1. Spring5源码深度解析(一)之理解Configuration注解

    代码地址:https://github.com/showkawa/spring-annotation/tree/master/src/main/java/com/brian 1.Spring体系结构 ...

  2. libevent源码深度剖析二

    libevent源码深度剖析二 ——Reactor模式 张亮 前面讲到,整个libevent本身就是一个Reactor,因此本节将专门对Reactor模式进行必要的介绍,并列出libevnet中的几个 ...

  3. spring5 源码深度解析----- 被面试官给虐懵了,竟然是因为我不懂@Configuration配置类及@Bean的原理

    @Configuration注解提供了全新的bean创建方式.最初spring通过xml配置文件初始化bean并完成依赖注入工作.从spring3.0开始,在spring framework模块中提供 ...

  4. spring5 源码深度解析----- Spring事务 是怎么通过AOP实现的?(100%理解Spring事务)

    此篇文章需要有SpringAOP基础,知道AOP底层原理可以更好的理解Spring的事务处理. 自定义标签 对于Spring中事务功能的代码分析,我们首先从配置文件开始人手,在配置文件中有这样一个配置 ...

  5. 惊人!Spring5 AOP 默认使用Cglib ?从现象到源码深度分析

    Spring5 AOP 默认使用 Cglib 了?我第一次听到这个说法是在一个微信群里: 真的假的?查阅文档 刚看到这个说法的时候,我是保持怀疑态度的. 大家都知道 Spring5 之前的版本 AOP ...

  6. spring5 源码深度解析----- @Transactional注解的声明式事物介绍(100%理解事务)

    面的几个章节已经分析了spring基于@AspectJ的源码,那么接下来我们分析一下Aop的另一个重要功能,事物管理. 事务的介绍 1.数据库事物特性 原子性多个数据库操作是不可分割的,只有所有的操作 ...

  7. spring5 源码深度解析----- 事务增强器(100%理解事务)

    上一篇文章我们讲解了事务的Advisor是如何注册进Spring容器的,也讲解了Spring是如何将有配置事务的类配置上事务的,实际上也就是用了AOP那一套,也讲解了Advisor,pointcut验 ...

  8. spring5 源码深度解析----- 事务的回滚和提交(100%理解事务)

    上一篇文章讲解了获取事务,并且通过获取的connection设置只读.隔离级别等,这篇文章讲解剩下的事务的回滚和提交 回滚处理 之前已经完成了目标方法运行前的事务准备工作,而这些准备工作最大的目的无非 ...

  9. ThreadLocal的原理,源码深度分析及使用

    文章简介 ThreadLocal应该都比较熟悉,这篇文章会基于ThreadLocal的应用以及实现原理做一个全面的分析 内容导航 什么是ThreadLocal ThreadLocal的使用 分析Thr ...

随机推荐

  1. Indexing Sensor Data

    In particular embodiments, a method includes, from an indexer in a sensor network, accessing a set o ...

  2. Win7使用初体验

    作者:朱金灿 来源:http://blog.csdn.net/clever101 最近装了个Win7旗舰版.随着年纪渐大,我对软件使用越来越趋于务实,不再追求最新版本,因为我评价一个好软件的标准是适用 ...

  3. Method and apparatus for establishing IEEE 1588 clock synchronization across a network element comprising first and second cooperating smart interface converters wrapping the network element

    Apparatus for making legacy network elements transparent to IEEE 1588 Precision Time Protocol operat ...

  4. .net reactor 学习系列(二)---.net reactor界面各功能说明

    原文:.net reactor 学习系列(二)---.net reactor界面各功能说明         安装了.net reactor之后,可以在安装目录下找到帮助文档REACTOR_HELP.c ...

  5. [AC自己主动机] zoj Searching the String

    意甲冠军: 到原始字符串.给n字符串,每个字符串都有一个属性,属性0代表重叠,1代表不能重叠 请各多少次出现的字符串 思维: 为了便于建立两台机器自己主动(0一个.1一个) 然后,它可以重叠非常好做, ...

  6. sql 从未连续的Id中选择10~30条数据

    select * from(select *,row_number()over(order by ProductID) as num from Products) as t where t.num&g ...

  7. php 二维数组相同值 相加

    array(3) { [0]=> array(2) { ["sourcesid"]=> int(1) ["addusernum"]=> str ...

  8. mingw 构建 mysql-connector-c-6.1.9记录(26种不同的编译错误,甚至做了一个windows系统返回错误码与System V错误码的一个对照表)

    http://www.cnblogs.com/oloroso/p/6867162.html

  9. Python标准库(3.x): 内建函数扫盲

    Built-in Functions abs() dict() help() min() setattr() all() dir() hex() next() slice() any() divmod ...

  10. 【Git】打标签

    打标签 同大多数 VCS 一样,Git 也可以对某一时间点上的版本打上标签.人们在发布某个软件版本(比如 v1.0 等等)的时候,经常这么做.本节我们一起来学习如何列出所有可用的标签,如何新建标签,以 ...