Spring(一)spring基础及组件使用1、2、3

仅以此记录spring学习笔记

 

spring框架:

spring --> IOC --> DI

Dog dog = new Dog();

IOC管理

IOC就是对bean进行管理:bean注册、实例化管理

application.xml --> <bean id = 'dog' class = "com.ca.Dog">

使用注解

IOC容器:Map

java bean实例

map.put(beanId,Bean)

多实例:仅当bean被使用的时候才创建。

单实例:创建IOC容器的时候实例bean就被创建了

 

@Configuration 配置类声明

告诉spring这是一个配置类

BeanId 就是配置bean的方法名

Bean可以修改自定义名@Bean("自定义名")

// 配置类  == 配置文件
@Configuration
public class MainConfig {

  // 给容器中注册一个bean,类型为返回值的类型
  @Bean("ABC")
  public Person person() {
    return new Person("yang", 13);
  }
}

 

@ComponentScan扫描规则

指定扫描范围:

注意:使用includeFilters必须将useDefaultFilters设为false

Filter[] includeFilters() default {};//包含 Filter[] excludeFilters() default {};//排除 //例子:按照注解过滤 @ComponentScan(value = "com.enjoy.cap2",excludeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Service.class})}, useDefaultFilters = true)

 

扫描过滤器:

Fileter的类型有:
/**
 * Filter candidates marked with a given annotation.
 * @see org.springframework.core.type.filter.AnnotationTypeFilter
 */
ANNOTATION,

/**
 * Filter candidates assignable to a given type.
 * @see org.springframework.core.type.filter.AssignableTypeFilter
 */
ASSIGNABLE_TYPE,

/**
 * Filter candidates matching a given AspectJ type pattern expression.
 * @see org.springframework.core.type.filter.AspectJTypeFilter
 */
ASPECTJ,

/**
 * Filter candidates matching a given regex pattern.
 * @see org.springframework.core.type.filter.RegexPatternTypeFilter
 */
REGEX,

/** Filter candidates using a given custom
 * {@link org.springframework.core.type.filter.TypeFilter} implementation.
 */
CUSTOM

 

自定义过滤规则:

@Configuration
@ComponentScan(
    value = "com.enjoy.cap2",
    includeFilters = {
      @ComponentScan.Filter(
          type = FilterType.CUSTOM,
          classes = {MyTypeFileter.class})
    },
    useDefaultFilters = false)
public class MainConfig {

  // 给容器中注册一个bean,类型为返回值的类型
  @Bean
  public Person person() {
    return new Person("yang", 13);
  }
}


public class MyTypeFileter implements TypeFilter {

  private ClassMetadata classMetadata;

  /*
   * metadataReader:读取到当前正在扫描类的信息
   * metadataReaderFactory:可以获取到其他任何类的信息
   */
  @Override
  public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
      throws IOException {
    // 获取当前类注解的信息
    AnnotatedTypeMetadata annotatedTypeMetadata = metadataReader.getAnnotationMetadata();
    // 获取当前正在扫描的类信息
    classMetadata = metadataReader.getClassMetadata();
    // 获取当前类资源(类的路径)
    Resource resource = metadataReader.getResource();

    String className = classMetadata.getClassName();
    System.out.println("--->" + className);
    if (className.contains("OderDao")) {
      return true;
    } else {
      return false;
    }
  }
}

 

@Scope扫描规则

1、单实例bean

2、多实例bean

3、request和session

直接使用@Bean注解时,默认是单实例的

@Configuration
@ComponentScan
public class Cap3MainConfig {
  // 给容器中注册一个bean,类型为返回值的类型  默认单实例
  /*
 * prototype: 多实例:IOC容器启动的时候,不会去调用方法创建对象,而是每次获取的时候才会调用方法创建对象
 * singleton: 单实例(默认):IOC容器启动的时候会调用方法创建对象,并且放入IOC容器中,即IOC的Map中,以后每次获取都是从容器中拿到同一个bean
 * request:主要针对web应用,递交一次请求创建一次实例
 * session:同一个session创建一个实例
*/
  @Scope("prototype")
  @Bean
  public Person person() {
    return new Person("yang", 13);
  }
}

 

@Lazy懒加载

1、什么是懒加载

2、懒加载如何获取容器中的bean

@Configuration
public class Cap4MainConfig {
  // 给容器中注册一个bean,类型为返回值的类型  默认单实例
  // 懒加载:主要针对单实例bean:默认在容器自启动的时候创建对象
  // 懒加载:容器启动的时候,不创建对象,仅当第一次使用(获取)bean的时候才创建被初始化,可解决循环service引用问题
  @Lazy
  @Bean
  public Person person() {
    return new Person("yang", 13);
  }
}

 

@Conditional条件注册bean

1、什么是条件注册bean

2、如何根据指定条件选择性地注册bean实例

需求:运行测试用例时,如果操作系统是windows,让lion这个对象实例化到容器中,如果是linux则让lisa实例化到容器中。

条件方法实现condition接口

示例代码

@Configuration
public class Cap5MainConfig {
  @Conditional(MacCondition.class)
  @Bean("lisa")
  public Person lisa() {
    System.out.println("给容器中添加lisa……");
    return new Person("lisa", 18);
  }
}
  
  /**
   * 条件匹配
   *
   * @param context
   *     <p>判断条件可以使用的上下文环境
   * @param metadata
   *     <p>注解信息
   * @return
   */
  @Override
  public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    // TODO 是否为windows操作系统
    // 从IOC容器中获取正在使用的beanFactory
    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    // 获取当前的环境变量,包括操作系统
    Environment environment = context.getEnvironment();
    // 取操作系统值,os.name是规范写法
    String osName = environment.getProperty("os.name");
    if (osName.contains("Mac OS X")) {
      return true;
    }
    return false;
  }
}

可以通过修改环境变量,修改osname

-Dos.name=windows

 

@Import注册bean

1、手动添加组件到IOC容器

2、使用ImportSelector自定义返回组件

3、使用ImportBeanDefinitionRegistroar返回自定义组件

4、FactoryBean接口实现

a、getObject()返回对象方法

b、getObjectType()返回对象类型

c、isSingleton()是否单例控制

 

factoryBean和BeanFactory有何区别:

factoryBean:可以把java实例Bean通过factoryBean注入到容器中。

beanFactory:从容器中获取实例化后的Bean。

示例代码
//配置类
@Configuration
@Import(value = {Dog.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class Cap6MainConfig {

   // 给容器中注册组件的方式
   // 1、@Bean:[导入第三方的类或包的组件],比如Person是第三方的类,需要再IOC容器中使用
   // 2、包扫描+组件的标注注解(@ComponentScan: @Controller,@Service @Reponsitory @Componet),一般是针对我们自己写的类
  // 3、@Import:[快速给容器导入一个组件],注意:@Bean比较简单,
  // 3.1、@Import(要导入到容器中的组件):容器会自动注册这个组件,bean的id为全类名
  // 3.2、ImportSelect接口:返回需要导入到容器中的组件全类名数组
  // 3.3、ImportBeanDefinitionRegistrar:可以手动添加组件到IOC容器,所有Bean的注册可以使用BeanDefinitionRegistry,写MyImportBeanDefinitionRegistrar实现这个接口即可
  // 3.4、使用spring提供的额FactoryBean接口(工厂bean)进行注册
  @Bean("yang")
  public Person person() {
    System.out.println("给容器中添加yang……");
    return new Person("yang", 13);
  }
}


public class MyImportSelector implements ImportSelector {
  @Override
  public String[] selectImports(AnnotationMetadata importingClassMetadata) {
    String[] myBean = new String[2];
    myBean[0] = "com.enjoy.cap6.bean.Cat";
    return myBean;
  }
}

/**
 * @author yangzhiji
 * @create 2021-01-13 9:28 PM
 */
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
  // AnnotationMetadata:当前类的注解信息
  // BeanDefinitionRegistry:BeanDefinition注册类
  // 把所有需要添加到容器中的bean加入
  @Override
  public void registerBeanDefinitions(
      AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    boolean bean = registry.containsBeanDefinition("com.enjoy.cap6.bean.Cat");
    // 如果cat存在于容器中,那么创建Pig类加入到容器中
    // 对于要注册的bean需要进行封装
    if (bean) {
      // 封装
      RootBeanDefinition beanDefinition = new RootBeanDefinition(Pig.class);
      // 注册
      registry.registerBeanDefinition("Pig", beanDefinition);
    }
  }
}


public class MyFactoryBean implements FactoryBean<Tiger> {
  @Override
  public Tiger getObject() throws Exception {
    return new Tiger();
  }
  @Override
  public Class<?> getObjectType() {
    return Tiger.class;
  }
  @Override
  public boolean isSingleton() {
    return true;
  }
}

 

什么是Bean的生命周期

Bean的生命周期值Bean创建-->初始化-->销毁的过程

我们可以自定义Bean初始化和销毁方法

容器在Bean进行到当前生命周期的时候,来调用自定义的初始化和销毁方法

生命周期-初始化与销毁1

1、制定初始化init-method方法

2、指定销毁destroy-method方法

注:

对于单实例的bean,可以正常调用初始化和销毁方法

对于多实例的bean,容器只负责初始化,但不会管理bean,容器关闭时不会调用销毁方法

populateBbean (property) //属性赋值

initionlation(bean)//初始化

CGLIB可以实例化对象,原理是动态代理

@Configuration
public class Cap7MainConfigOflifeCycle {
  @Bean("yang")
  public Person person() {
    System.out.println("给容器中添加yang……");
    return new Person("yang", 13);
  }
  @Bean(initMethod = "init", destroyMethod = "destroy")
  public Dog dog() {
    return new Dog();
  }
}

生命周期-初始化与销毁2

1、实现InitializingBean接口的afterPropertiesSet()方法,当beanFactory创建好对象,且把bean所有属性设置好之后,才会调用这个方法,相当于初始化方法。

2、实现disposableBean的destroy方法,当bean销毁时,,会把单实例bean进行销毁。

@Component
public class Cat implements InitializingBean, DisposableBean {
  public Cat() {
    System.out.println("给容器中添加cat。。。。");
  }
  public void init() {
    System.out.println("cat初始化方法。。。");
  }
  @Override
  public void destroy() {
    System.out.println("实现DisposableBean销毁方法。。。");
  }
  @Override
  public void afterPropertiesSet() throws Exception {
    System.out.println("实现InitializingBean创建bean之后执行的方法。。");
  }
}

生命周期-初始化与销毁3

可以使用JSR250规范(JAVA规范)定义的两个注解来实现:

@PostConstruct:在Bean创建完成,且属于赋值完成之后进行初始化,属于JDK规范的注解。

@Predestroy:在bean将被移除之前进行通知,在容器销毁之前进行清理工作

@Component
public class Tiger {
  public Tiger() {
    System.out.println("给容器中添加Tiger。。。。");
  }
  @PostConstruct
  public void init() {
    System.out.println("Tiger初始化方法。。。");
  }
  @PreDestroy
  public void destroy() {
    System.out.println("Tiger销毁方法。。。");
  }
}

 

生命周期-BeanPostProcessor

bean的后置处理器,在bean初始化之前调用进行拦截,在bean初始化前后进行一些处理工作,使用BeanPostProcessor如何控制Bean的生命周期?实现BeanPostProcessor接口的两个方法即可:

1、postProcessBeforeInitialization()

2、postProcessAfterInitialization()

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName)
      throws BeansException {
    // 返回一个传过来的对象
    // 初始化方法调用之前进行后置处理工作
    // 什么时候调用它:init-method = init之前调用
    System.out.println("postProcessBeforeInitialization..." + beanName);
    return bean;
  }
  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("postProcessAfterInitialization..." + beanName);
    return bean;
  }
}

spring可以针对方法进行拦截增强

BeanPostProcessor源码初步分析

使用BeanPostProcessor如何控制Bean的生命周期

 

 

 

 

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页