Spring由浅入深(上)

86 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第31天,点击查看活动详情

一、Spring

  1. spring编程模型

  1. spring的核心价值
  • 设计思想
  • 设计模式
  • 用户基础
  • 生态系统
  • api抽象设计
  • 编程模型
  1. spring中的设计模式

  2. Spring Framework有哪些核心模块

  • spring-core:Spring基础API模块,如资源管理,泛型处理
  • spring-beans:Spring Bean相关,如依赖查找,依赖注入
  • spring-aop:Spring AOP处理,如动态代理,AOP字节码提升
  • spring-context:事件驱动、注解驱动,模块驱动
  • spring-expression:Spring表达式语言模块

二、IoC

  1. 什么是IoC?

是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。简单的说就是控制反转。其中最常见的实现方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。 2. IoC容器的职责

  • 依赖处理
    • 依赖查找
    • 依赖注入
  • 生命周期管理
    • 容器
    • 托管的资源
  • 配置
    • 容器
    • 外部化配置
    • 托管的资源
  1. IoC容器的实现

  1. 传统的Java Beans实现

获取bean的属性

 BeanInfo beanInfo = Introspector.getBeanInfo(User.class, Object.class);
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        for (PropertyDescriptor propertyDescriptor:propertyDescriptors){
            String propertyDescriptorName = propertyDescriptor.getName();
            System.out.println(propertyDescriptorName);
        }
  1. 依赖注入 VS 依赖查找
类型依赖处理实现便利性代码侵入性API依赖性可读性
依赖查找主动获取相对繁琐侵入业务逻辑依赖容器API良好
依赖注入被动提供相对便利低侵入性不依赖容器API一般
  1. 构造器注入 VS Setter注入

Seeter注入的优点:

  • 如果依赖关系较为复杂,那用构造函数注入的化会相对庞大

构造器注入的优点:

  • 避免了繁琐的stter方法编写
  • 符合了“在构造期即创建一个完整、合法的对象”的设计原则
  • 由于没有setter方法的编写,组件创建后就处于“不变”的稳定状态,能够避免很多问题
  • 通过构造器注入,意味着构造函数中决定了依赖关系的注入顺序,对于大量依赖外部服务的组件而言,依赖关系的获得顺序非常重要。

依赖查找


public class Demo {

    public static void main(String[] args) {
        BeanFactory beanFactory = new ClassPathXmlApplicationContext("dependency-lookup-context.xml");
        lookupInLazyTime(beanFactory);
        lookupCollection(beanFactory);
        lookupByAnnotationType(beanFactory);
    }

    private static void lookupByAnnotationType(BeanFactory beanFactory) {
        if(beanFactory instanceof ListableBeanFactory){
            ListableBeanFactory listableBeanFactory=(ListableBeanFactory)beanFactory;
            Map<String, Object> beans = listableBeanFactory.getBeansWithAnnotation(Super.class);
            System.out.println(beans);
        }
    }

    private static void lookupCollection(BeanFactory beanFactory) {
        if(beanFactory instanceof ListableBeanFactory){
            ListableBeanFactory listableBeanFactory=(ListableBeanFactory)beanFactory;
            Map<String, Person> personMap = listableBeanFactory.getBeansOfType(Person.class);
            System.out.println(personMap);
        }
    }

    //实时查找
    private static void lookupInRealTime(BeanFactory beanFactory) {
        Person person = (Person) beanFactory.getBean("person");
        System.out.println(person);
    }

    //延迟查找
    private static void lookupInLazyTime(BeanFactory beanFactory) {
        ObjectFactory<Person> objectFactory = (ObjectFactory<Person>)beanFactory.getBean("objectFactory");
        Person person = objectFactory.getObject();
        System.out.println(person);
    }


}

依赖注入:

  <bean id="userRepository" class="com.mmc.repository.UserRepository" autowire="byType"></bean>
  1. BeanFactory vs ApplicationContext
  • BeanFactory是底层IoC容器
  • ApplicationContext是具备应用特性的BeanFactory超集
  1. ApplicationContext除了是IOC容器外,还能提供:
  • 面向切面(AOP)
  • 配置元信息
  • 资源管理
  • 事件
  • 国际化
  • 注解
  • Environment抽象

使用demo:

public class ApplicationDemo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext();
        applicationContext.register(ApplicationDemo.class);
        applicationContext.refresh();
        Person bean = applicationContext.getBean(Person.class);
        System.out.println(bean);
    }

    @Bean
    public Person person(){
        Person person = new Person();
        person.setAge(12);
        person.setName("小慢");
        return person;
    }
}
  1. BeanFactory 与 FactoryBean?
  • BeanFactory 是IoC底层容器
  • FactoryBean 是创建Bean的一种方式,帮助实现复杂的初始化逻辑
  1. BeanFacory的运用
 public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory=new DefaultListableBeanFactory();
        XmlBeanDefinitionReader beanDefinitionReader=new XmlBeanDefinitionReader(beanFactory);
        beanDefinitionReader.loadBeanDefinitions("dependency-lookup-context.xml");
        System.out.println(Arrays.asList(beanFactory.getBeanDefinitionNames()));
        Person person = (Person)beanFactory.getBean("person");
        System.out.println(person);

    }

三、Spring Bean

  1. BeanDefintion元信息

  2. Bean定义的方式

BeanDefinitionBuilder beanDefinitionBuilder=BeanDefinitionBuilder.genericBeanDefinition(Person.class);
        beanDefinitionBuilder.addPropertyValue("name","小哥");
        AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        System.out.println(beanDefinition);
  1. 注册Spring Bean
  • XML配置方式
    • <bean name="" ...>
  • Java注解配置方式
    • @Bean
    • @Component
    • @Import
@Import(AnnotationRegisterBeanDemo.Config.class)
public class AnnotationRegisterBeanDemo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(AnnotationRegisterBeanDemo.class);
        applicationContext.refresh();
        System.out.println(applicationContext.getBean(Config.class));
        System.out.println(applicationContext.getBean(User.class));
        applicationContext.close();
    }


    @Component
    public static class Config{

        @Bean
        public User user(){
            User user=new User();
            user.setName("实施");
            return user;
        }

    }
}

  • Java Api配置方式
    • BeanDefinitionRegistry#registerBeanDefinition
    • BeanDefinitionReaderUtils#registerWithGeneratedName
    • AnnotationConfigApplicationContext#register
 public static void registerBeanDefinition(BeanDefinitionRegistry registry,String beanName,Class<?> beanClass){
        BeanDefinitionBuilder beanDefinitionBuilder=BeanDefinitionBuilder.genericBeanDefinition(beanClass);
        beanDefinitionBuilder.addPropertyValue("name","wanger");
        if(StringUtils.hasText(beanName)){
            registry.registerBeanDefinition(beanName,beanDefinitionBuilder.getBeanDefinition());
        }else {
            BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinitionBuilder.getBeanDefinition(),registry);
        }
    }

    public static void registerBeanDefinition(BeanDefinitionRegistry registry,Class<?> beanClass){
        registerBeanDefinition(registry,null,beanClass);
    }
  1. 实例化Bean
  • 标准方式
    • 通过构造器
    • 通过静态工厂方法
    • 通过Bean工厂
    • 通过FactoryBean
  • 特殊方式
    • ServiceLoader 在MEAT-INF/services
      目录下创建一个文件,以接口的全路径为文件名,内容为实现类的全路径
public class ServiceLoaderDemo {

    public static void main(String[] args) {
        ServiceLoader<UserFactory> serviceLoader=ServiceLoader.load(UserFactory.class, Thread.currentThread().getContextClassLoader());
        Iterator<UserFactory> iterator = serviceLoader.iterator();
        while (iterator.hasNext()){
            UserFactory next = iterator.next();
            System.out.println(next.createUser());
        }
    }
}
  1. SpringBean的初始化
  • @PostConstruct
  • Bean initMethod
  • 实现InitializingBean接口
  • AbstractBeanDefinition#setInitMethodName
  1. Spring的延迟加载
  • XML配置:lazy-init="true"
  • @Lazy注解
  1. SpringBean的销毁
  • @PreDestroy
  • 实现DisposableBean接口
  • @Bean的destroyMethod