互联网架构-Spring5.0源码深度解析-020:Spring核心注解

1 常用注解源码分析课程安排

课程内容:
1、使用@Condition多条件注册bean对象
2、@Import注解快速注入第三方bean对象
3、深度分析SpringBoot EnableXXX注册底层实现原理
4、基于ImportBeanDefinitionRegistrar注册bean
5、基于FactoryBean注册bean对象
6、FactoryBean与BeanFactory之间的区别

为什么@Enablexxx能够自动注入bean的对象?
通过@Import注解进行整合。

FactoryBean与BeanFactory有什么区别?
FactoryBean主要是做注册对象,BeanFactory主要是做获取对象。

2 @Condition条件注册bean使用

@Condition
Condition 是在spring4.0 增加的条件注解,通过这个可以功能可以实现选择性的注入Bean操作。

实现案例
在Spring容器加载中,如果当前环境是WIN10操作系统就装配win10实体类、其他系统就不装配。
实体类

public class Win10Entity {
    // 只有在当前运行到win10环境,才会注入到spring ioc容器中
}

配置类

@Configuration
public class MyConfig {
    @Bean
    @Conditional({MyCondition.class})
    public Win10Entity win10Entity(){
        return new Win10Entity();
    }
}

Condition配置

public class MyCondition implements Condition {
    /**
     *
     * @param conditionContext  获取到当前的上下文
     * @param annotatedTypeMetadata  获取当前注解的信息
     * @return
     */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        Environment environment = conditionContext.getEnvironment();
        String property = environment.getProperty("os.name");
        if ("Windows 10".equals(property)) {
            return true;
        }
        return false;
        // return true 可以注册改对象
        // return false 不能注册改对象
    }
}

测试类

public class V1Spring {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
        Win10Entity win10Entity = (Win10Entity) applicationContext.getBean("win10Entity");
        System.out.println(win10Entity); //com.mayikt.v1.entity.Win10Entity@12405818
    }
}

修改代码Conditoin类控制条件

public class MyCondition implements Condition {
    /**
     *
     * @param conditionContext  获取到当前的上下文
     * @param annotatedTypeMetadata  获取当前注解的信息
     * @return
     */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        Environment environment = conditionContext.getEnvironment();
        String property = environment.getProperty("os.name");
        if ("Windows 10".equals(property)) {
            return false;
        }
        return true;
        // return true 可以注册改对象
        // return false 不能注册改对象
    }
}

运行结果:
在这里插入图片描述

3 @Import注解与@Bean注解区别

为什么要使用@Import注解?
@Bean应用场景:注册加载外部jar包,代码冗余。

@Import注解
@Import是用来整合所有在@Configuration注解中定义的bean配置;
默认注册beanid为 全路径地址

实验案例
配置类

@Configuration
@Import(Win10Entity.class)
public class MyConfig {
    // Import作用主要是将外部的jar包注入到springioc容器中 @Import(Win10Entity.class)等同于@Bean
    // Import注册的bean对象 id为当前类全路径
}

启动类

public class V1Spring {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
        Win10Entity win10Entity = (Win10Entity) applicationContext.getBean("com.mayikt.v1.entity.Win10Entity");
        System.out.println(win10Entity);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for(String i : beanDefinitionNames){
            System.out.println(i);
        }

    }
}

运行结果:
在这里插入图片描述
总结:@Import注解与@Bean注解区别
Bean注解注册的bean的id是以方法名称 @Import以当前类完整路径地址注册,相对来说@Import注入类更加方便
共同应用场景:都是引入外部的jar包

4 @EnableXXX功能性注解实现原理

需要注入的bean

public class PayEntity {
}
public class MyPayEntity {
}

EnablePayEntity注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({PayEntity.class, MyPayEntity.class})
public @interface EnablePayEntity {
    // 只要在启动的时候加入该EnablePayEntity 就会将PayEntity实体类注入到spring ioc容器
    // 使用Enable注解的话,底层实际上在调用@Import(PayEntity.class)
    // 内部开发一个框架,目前不支持SpringBoot,可以使用Enablexxx注入
}

配置类

@Configuration
@EnablePayEntity
public class MyConfig {
}

运行结果:
在这里插入图片描述

5 使用实现ImportSelector注册bean

ImportSelector
ImportSelector接口是至spring中导入外部配置的核心接口,在SpringBoot的自动化配置和@EnableXXX(功能性注解)都有它的存在

实验案例
需要注入的bean

public class MemberEntity {
}
public class MsEntity {
}

MyImportSelector

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{"com.mayikt.v1.entity.MemberEntity","com.mayikt.v1.entity.MsEntity"};
    }
}

配置类

@Configuration
@Import(MyImportSelector.class)
public class MyConfig {
}

运行结果:
在这里插入图片描述

6 使用ImportBeanDefinitionRegistrar注册bean

ImportBeanDefinitionRegistrar手动注册bean

实验案例
需要注入的bean

public class SmsEntity {
}

ImportBeanDefinitionRegistrar手动注册

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    /**
     *
     * @param annotationMetadata 注解的信息
     * @param beanDefinitionRegistry
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        // spring容器中 bean的信息都是有BeanDefinition描述  手动注册到ioc容器中
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(SmsEntity.class);
        beanDefinitionRegistry.registerBeanDefinition("smsEntity",rootBeanDefinition);
        // spring ioc 底层通过beanDefinitionMap存放 线程是安全的
    }
}

配置类 或者MyImportBeanDefinitionRegistrar类上加注解@Component注入

@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class MyConfig {
}

运行结果:
在这里插入图片描述

7 使用FactoryBean注册对象

FactoryBean与BeanFactory区别
FactoryBean往ioc容器中存储对象 注入对象
BeanFactory从ioc工厂中获取bean对象

BeanFactory是个Factory,也就是IOC容器或对象工厂,在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。
对FactoryBean而言,首先它是个Bean,但这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似。

实验案例
需要注入的bean

public class MyEntity {
}

MyFactoryBean

public class MyFactoryBean implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        return new MyEntity();
    }

    @Override
    public Class<?> getObjectType() {
        return MyEntity.class;
    }
    // 往IOC容器中注入对象

    @Override
    public boolean isSingleton() {
        // 默认情况为true,为单例;false为多例
        return true;
    }
}

配置类

@Configuration
public class MyConfig {
    @Bean
    public MyFactoryBean myFactoryBean(){
        return new MyFactoryBean();
    }
}

测试类

public class V1Spring {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
        MyEntity myFactoryBean1 = (MyEntity) applicationContext.getBean("myFactoryBean");
        MyEntity myFactoryBean2 = (MyEntity) applicationContext.getBean("myFactoryBean");
        System.out.println(myFactoryBean1 == myFactoryBean2); //true
    }
}

8 @Service与@Compent注解区别

@Service、@Repository等注入对象底层还是使用@Component进行注入,只是为了更好的区分应用场景,注意要加上扫包范围

实验案例 编写类似@Service功能的注解
自定义注解@Mayikt

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Mayikt {
}

需要注入的bean

@Mayikt
public class MayiktEntity {
}

配置类

@Configuration
@ComponentScan("com.mayikt.v1.entity")
public class MyConfig {
}

运行结果:
在这里插入图片描述

9 @Primary与@Qualifier区别

一个接口下有两个实现类,如果用@Autowired进行获取

public interface UserService {
    public void add();
}
@Component
public class UserServiceImpl01 implements UserService {
    @Override
    public void add() {
        System.out.println("UserServiceImpl01");
    }
}
@Component
public class UserServiceImpl02 implements UserService {
    @Override
    public void add() {
        System.out.println("UserServiceImpl02");
    }
}

引用类

@Component
public class OrderService {

    @Autowired
    private UserService userService;

    public void add() {
        userService.add();
    }
}

配置类

@Configuration
@ComponentScan(value="com.mayikt")
public class MyConfig {
}

启动类

public class V1Spring {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
        OrderService orderService = (OrderService) applicationContext.getBean("orderService");
        orderService.add();
    }
}

运行结果:
在这里插入图片描述
因为@Autowired默认的情况下使用类型查找

3种方案默认使用UserServiceImpl02类:

  1. @Resource设置根据名称进行查找
@Component
public class OrderService {

    @Autowired
    @Resource(name = "userServiceImpl02")
    private UserService userService;

    public void add() {
        userService.add();
    }
}
  1. @Qualifier根据名称进行查找
@Component
public class OrderService {

    @Autowired
    @Qualifier("userServiceImpl02")
//    @Resource(name = "userServiceImpl02")
    private UserService userService;

    public void add() {
        userService.add();
    }
}
  1. @Primary设置默认类 类似SpringBoot多数据源 设置默认的数据源(优先级)
@Component
@Primary
public class UserServiceImpl02 implements UserService {
    @Override
    public void add() {
        System.out.println("UserServiceImpl02");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值