这篇文章将为大家详细讲解有关怎么深度解析Spring5.0源码,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。
这篇文章主要针对Spring核心注解进行分析
Condition 是在spring4.0 增加的条件注解,通过这个可以功能可以实现选择性的注入Bean操作,接下来先学习下Condition是如何使用的,然后分析spring源码了解其中的实现原理。
实现案例:
在Spring容器加载中,如果当前环境是WIN7操作系统就装配win7实体类、其他系统就不装配。
@Configuration
public class MyConfig {
/**
* Import作用主要将外部的jar包注入到springioc容器中 @Import(Win7Entity.class) 等于与@Bean
* Import注册的bean对象 id为当前类全路径
*/
@Bean
public Win7Entity win7Entity() {
return new Win7Entity();
}
public class V1Spring {
public static void main(String[] args) {
// 1.基于注解方式实现启动
ApplicationContext annotationApplicationContext =
new AnnotationConfigApplicationContext(MyConfig.class);
Win7Entity win7Entity = (Win7Entity) annotationApplicationContext.getBean("win7Entity");
System.out.println(win7Entity);
输出结果
com.mayikt.v1.entity.Win7Entity@5606c0b
MyCondition
public class MyCondition implements Condition {
/**
* @param context 获取到当前的上下文
* @param metadata 获取当前注解的细心
* @return
*/
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 1.获取当前的环境
Environment environment = context.getEnvironment();
// win7 linux win8 win10 苹果系统MAC
String osName = environment.getProperty("os.name");
if (osName.equals("Windows 10")) {
// 可以注册该对象
return true;
}
// 不能注册该对象
return false;
}
}
@Configuration
public class MyConfig {
/**
* Import作用主要将外部的jar包注入到springioc容器中 @Import(Win7Entity.class) 等于与@Bean
* Import注册的bean对象 id为当前类全路径
*/
@Bean
@Conditional(MyCondition.class)
public Win7Entity win7Entity() {
return new Win7Entity();
}
输出:
com.mayikt.v1.entity.Win7Entity@64d7f7e0
1.为什么要使用@Import注解?Import注解的主要作用的将外部的jar包注入到springioc容器中
2.@Bean注解应用场景是什么?注册加载外部jar包
@Configuration
@Import(Win7Entity.class)
public class MyConfig {
/**
* Import作用主要将外部的jar包注入到springioc容器中 @Import(Win7Entity.class) 等同于@Bean
* Import注册的bean对象 id为当前类全路径
*/
/* @Bean
@Conditional(MyCondition.class)
public Win7Entity win7Entity() {
return new Win7Entity();
}*/
public class V1Spring {
public static void main(String[] args) {
// 1.基于注解方式实现启动
ApplicationContext annotationApplicationContext =
new AnnotationConfigApplicationContext(MyConfig.class);
Win7Entity win7Entity = (Win7Entity) annotationApplicationContext.getBean("com.mayikt.v1.entity.Win7Entity");//这里当前类Win7Entity的全路径
System.out.println(win7Entity);
结果:
com.mayikt.v1.entity.Win7Entity@f4168b8
public class V1Spring {
public static void main(String[] args) {
// 1.基于注解方式实现启动
ApplicationContext annotationApplicationContext =
new AnnotationConfigApplicationContext(MyConfig.class);
Win7Entity win7Entity = (Win7Entity) annotationApplicationContext.getBean("com.mayikt.v1.entity.Win7Entity");
System.out.println(win7Entity);
String[] beanDefinitionNames = annotationApplicationContext.getBeanDefinitionNames();
for (int i = 0; i < beanDefinitionNames.length; i++) {
System.out.println(beanDefinitionNames[i]);
}
结果
com.mayikt.v1.entity.Win7Entity@f4168b8
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
myConfig
com.mayikt.v1.entity.Win7Entity
总结下:@Bean注解与@Import注解的区别?
@Bean注解注册的bean的id是以方法名称来作为beanid ,
@Import注解以当前类的完整路径地址注册 ,相比来说@Import注入类更加简单
应用场景都是引入外部jar包
配合@Configuration使用,包括 @EnableAsync, @EnableScheduling, @EnableTransactionManagement, @EnableAspectJAutoProxy, @EnableWebMvc。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({PayEntity.class,MyPayEntity.class}) //引入@Import注解
public @interface EnablePayEntity {
// 只要启动的时候 加入该EnablePayEntity 就会将PayEntity实体类注入到spruingioc容器
// Enable注解的话 底层 实际上在调用@Import(PayEntity.class)
}
@Configuration
@Import(Win7Entity.class)
@EnablePayEntity //配置类加上这个注解
public class MyConfig {
/**
* Import作用主要将外部的jar包注入到springioc容器中 @Import(Win7Entity.class) 等于与@Bean
* Import注册的bean对象 id为当前类全路径
*/
程序输出结果
com.mayikt.v1.entity.Win7Entity@130f889
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
myConfig
com.mayikt.v1.entity.PayEntity
com.mayikt.v1.entity.MyPayEntity
com.mayikt.v1.entity.Win7Entity
@EnableXXX注解的实现原理:底层实际上还是调用@Import注解
public class MyImportSelector implements ImportSelector {
/**
* 注解信息
* @param importingClassMetadata
* @return
*/
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//注入多个对象,类的完整路径
return new String[]{"com.mayikt.v1.entity.MemberEntity","com.mayikt.v1.entity.MsEntity"};
}
}
@Configuration
@Import({Win7Entity.class,MyImportSelector.class})
@EnablePayEntity
public class MyConfig {
/**
* Import作用主要将外部的jar包注入到springioc容器中 @Import(Win7Entity.class) 等于与@Bean
* Import注册的bean对象 id为当前类全路径
*/
输出结果
com.mayikt.v1.entity.Win7Entity@16267862
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
myConfig
com.mayikt.v1.entity.PayEntity
com.mayikt.v1.entity.MyPayEntity
com.mayikt.v1.entity.Win7Entity
com.mayikt.v1.entity.MemberEntity
com.mayikt.v1.entity.MsEntity
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* AnnotationMetadata 注解的信息
* @param importingClassMetadata
* @param registry
*/
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// spring容器中 bean 的信息 Bean Definition描述 手动注册到ioc容器中
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(SmsEntity.class);
registry.registerBeanDefinition("smsEntity", rootBeanDefinition);
// 底层源码:springioc 底层通过beanDefinitionMap存放 线程是安全的
}
//FactoryBean (往IOC容器存储对象 注入对象) BeanFactory(从ioc工厂获取bean对象)
}
this.beanDefinitionMap.put(beanName, beanDefinition);
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256)
底层通过一个ConcurrentHashMap保存起来的。
@Configuration
@Import({Win7Entity.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})
@EnablePayEntity
public class MyConfig {
/**
* Import作用主要将外部的jar包注入到springioc容器中 @Import(Win7Entity.class) 等于与@Bean
* Import注册的bean对象 id为当前类全路径
*/
输出结果
myConfig com.mayikt.v1.entity.PayEntity com.mayikt.v1.entity.MyPayEntity com.mayikt.v1.entity.Win7Entity com.mayikt.v1.entity.MemberEntity com.mayikt.v1.entity.MsEntity smsEntity
public class MyFactoryBean implements FactoryBean<MyEntity> {
public MyEntity getObject() throws Exception {
return new MyEntity();
}
public Class<?> getObjectType() {
return MyEntity.class;
}
//往IOC容器中注入对象
public boolean isSingleton() {
// 默认的情况下就是为true true表示为单例 false 表示为多例
return false;
}
}
@Configuration
@Import({Win7Entity.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class,MyFactoryBean.class})
@EnablePayEntity
public class MyConfig {
/**
* Import作用主要将外部的jar包注入到springioc容器中 @Import(Win7Entity.class) 等于与@Bean
* Import注册的bean对象 id为当前类全路径
*/
输出结果
myConfig
com.mayikt.v1.entity.PayEntity
com.mayikt.v1.entity.MyPayEntity
com.mayikt.v1.entity.Win7Entity
com.mayikt.v1.entity.MemberEntity
com.mayikt.v1.entity.MsEntity
com.mayikt.v2.config.MyFactoryBean
smsEntity
BeanFactory是个Factory,也就是IOC容器或对象工厂,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。
但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似
底层还是调用@Compont注解,主要是为了分类,更好划分场景,注意要加上扫包范围
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Mayikt { }
在学习@Autowired的时候我们已经接触到了@Qualifier,这节就来详细学习一下自定义@Qualifier。
例如定义一个交通工具类:Vehicle,以及它的子类Bus和Sedan。
如果用@Autowired来找Vehicle的话,会有两个匹配的选项Bus和Sedan。为了限定选项,可以像下面这样。
@Autowired
@Qualifier("car")
private Vehicle vehicle;
如果要频繁使用@Qualifier("car")并且想让它变得更有意义,我们可以自定义一个@Qualifier。
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Car{
}
@Autowired
@Car
private Vehicle vehicle;
@Car
public class Sedan implements Vehicle{
}
在一个接口下有两个实现类使用@Autowired获取的时候,有什么问题?
@Autowired默认情况下使用类型查找,会存在问题。SpringBoot多数据源 设置默认或者优先级。
解决方案:
@Resource按照名称查找;
@Qualifier指定实现类
@Primary指定实现类的优先级第一,默认获取
关于怎么深度解析Spring5.0源码就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://my.oschina.net/u/3995125/blog/3080171