Spring注解-IOC

Spring注解-IOC

组件注册

@Configuration&@Bean

@Configuration:声明一个配置类

@Bean:向容器中注册bean,bean的类型为方法返回值类型,ID默认就是方法名。可以通过修改@Bean注解的value属性或者方法名来修改beanID

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

    //向容器中注册bean,类型为返回值类型,ID默认就是方法名
    @Bean("person")
    public Person person01(){
        return new Person("zhangsan",23);
    }
}
public class MainTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        Person person = applicationContext.getBean(Person.class);
        System.out.println(person);

        String[] beanNamesForType = applicationContext.getBeanNamesForType(Person.class);
        for (int i = 0; i < beanNamesForType.length; i++) {
            System.out.println(beanNamesForType[i]);
        }
    }
}

image-20210925170531150

  • 使用Spring提供的FactoryBean:默认获取到的是FactoryBean调用getObject返回的对象,想要获取FactoryBean本身,需要在bean id前加“&”

    @Configuration
    @Import({MyImportBeanDefinitionRegistrar.class})
    public class MainConfig3 {
    
        @Bean
        public MyFactoryBean myFactoryBean() {
            return new MyFactoryBean();
        }
    }
    
    public class MyFactoryBean implements FactoryBean<Product> {
        @Override
        public Product getObject() throws Exception {
            return new Product();
        }
    
        @Override
        public Class<?> getObjectType() {
            return Product.class;
        }
    
        @Override
        public boolean isSingleton() {
            return true;
        }
    }
    
    @Test
    public void mainConfig3Test() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig3.class);
        Object bean = context.getBean("myFactoryBean");
        System.out.println("bean的类型:"+bean.getClass());
    }
    

    image-20211003151445649

    @Test
    public void mainConfig3Test() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig3.class);
        Object bean = context.getBean("&myFactoryBean");
        System.out.println("bean的类型:"+bean.getClass());
    }
    

    image-20211003152207906

@ComponentScan

@ComponentScan:指定包扫描的路径。可以把指定路径下标注了@Controller、@Repository、@Service、@Component注解的类加到容器中。可以通过includeFilters和excludeFilters来指定添加和剔除哪些组件。

//配置类=配置文件
@Configuration
@ComponentScan(value = "com.hjw", excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {Dao.class})
})
//FilterType.ANNOTATION:按注解过滤
//FilterType.ASSIGNABLE_TYPE:按类型过滤
//FilterType.CUSTOM:自定义规则
public class MainConfig {

    //向容器中注册bean,类型为返回值类型,ID默认就是方法名
    @Bean("person")
    public Person person01(){
        return new Person("zhangsan",23);
    }
}
public class IOCTest {
    @Test
    public void test1(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
        String[] names = context.getBeanDefinitionNames();
        for (int i = 0; i < names.length; i++) {
            System.out.println(names[i]);
        }
    }
}
@org.springframework.stereotype.Controller
public class Controller {
}
@org.springframework.stereotype.Service
public class Service {
}
@Repository
public class Dao {
}

image-20210925214928722

自定义FilterType
public enum FilterType {

   /**
    * 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

}

通过实现org.springframework.core.type.filter.TypeFilter来自定义过滤器

public class MyFilter implements TypeFilter {
    /**
     *
     * @param metadataReader 当前正在扫描的类信息
     * @param metadataReaderFactory 可以获取到其他类信息
     * @return
     * @throws IOException
     */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        // 当前类的注解信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        // 当前类信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        String className = classMetadata.getClassName();
        System.out.println("当前扫描到的类名:"+className);
        return false;
    }
}

image-20210925221657908

@Scope

  • singleton:单例的(默认值),容器启动时会创建对象放在容器中,以后每次获取都是从容器中拿。

    @Configuration
    public class MainConfig2 {
    
        @Bean
        public Person person(){
            System.out.println("创建person");
            return new Person("李四", 18);
        }
    }
    
    @Test
    public void scopeTest() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
        Object p1 = context.getBean("person");
        Object p2 = context.getBean("person");
        System.out.println(p1 == p2);
    }
    

image-20210929202130079

  • prototype:多实例的,容器启动时不会创建对象,每次获取的时候才创建对象

    @Configuration
    public class MainConfig2 {
    
        @Scope("prototype")
        @Bean
        public Person person(){
            System.out.println("创建person");
            return new Person("李四", 18);
        }
    }
    

    image-20210929202458197

    image-20210929202529303

  • request:同一个请求创建一个实例

  • session:同一个session创建一个实例

@Lazy

单实例bean,默认在容器启动的时候创建对象。懒加载:容器启动时不创建对象。第一次获取bean时才创建对象,并初始化。

@Lazy
@Bean
public Person person(){
    System.out.println("创建person");
    return new Person("李四", 18);
}
    @Test
    public void scopeTest() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
        System.out.println("容器创建完成");
//        Object p1 = context.getBean("person");
//        Object p2 = context.getBean("person");
//        System.out.println(p1 == p2);
    }

image-20211001225740118

打开注解时

image-20211001230214403

@Conditional

按照一定条件进行判断,满足条件则给容器中注册bean

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {

   /**
    * All {@link Condition}s that must {@linkplain Condition#matches match}
    * in order for the component to be registered.
    */
   Class<? extends Condition>[] value();

}

可以作用在类和方法上,值Condition类

public class MyConditional implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        BeanDefinitionRegistry registry = context.getRegistry();
        return registry.containsBeanDefinition("person");
    }
}
@Configuration
public class MainConfig2 {

//    @Scope("prototype")
//    @Lazy
//    @Bean
//    public Person person(){
//        System.out.println("创建person");
//        return new Person("李四", 18);
//    }

    @Conditional({MyConditional.class})
    @Bean
    public Person james() {
        System.out.println("创建James");
        return new Person("james", 23);
    }

    @Bean
    public Person kobe() {
        System.out.println("创建Kobe");
        return new Person("Kobe", 24);
    }
}
@Test
public void scopeTest() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
    System.out.println("容器创建完成");
}

image-20211001234329596

@Import

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {

   /**
    * {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
    * or regular component classes to import.
    */
   Class<?>[] value();

}
  1. @Import(要导入容器的组件),id默认是全类名

    @Configuration
    @Import({Person.class})
    public class MainConfig2 {
    
    //    @Scope("prototype")
    //    @Lazy
    //    @Bean
    //    public Person person(){
    //        System.out.println("创建person");
    //        return new Person("李四", 18);
    //    }
    
    //    @Conditional({MyConditional.class})
        @Bean
        public Person james() {
            System.out.println("创建James");
            return new Person("james", 23);
        }
    
        @Bean
        public Person kobe() {
            System.out.println("创建Kobe");
            return new Person("Kobe", 24);
        }
    }
    
    @Test
    public void scopeTest() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
        System.out.println("容器创建完成");
        String[] definitionNames = context.getBeanDefinitionNames();
        for (int i = 0; i < definitionNames.length; i++) {
            System.out.println(definitionNames[i]);
        }
    }
    

    image-20211003104244152

  2. ImportSelector:返回要导入组件的全类名

    public interface ImportSelector {
    
       /**
        * Select and return the names of which class(es) should be imported based on
        * the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
        * @return the class names, or an empty array if none
        */
       String[] selectImports(AnnotationMetadata importingClassMetadata);
    
    }
    
    @Configuration
    @Import({MyImportSelect.class})
    public class MainConfig3 {
    }
    
    public class MyImportSelect implements ImportSelector {
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            return new String[]{"com.hjw.bean.person","com.hjw.bean.animal"};
        }
    }
    
    @Test
    public void mainConfig3Test() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig3.class);
        String[] definitionNames = context.getBeanDefinitionNames();
        for (int i = 0; i < definitionNames.length; i++) {
            System.out.println(definitionNames[i]);
        }
    }
    

在这里插入图片描述

  1. ImportBeanDefinitionRegistrar:手动注册

    public interface ImportBeanDefinitionRegistrar {
    
       /**
        * Register bean definitions as necessary based on the given annotation metadata of
        * the importing {@code @Configuration} class.
        * <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
        * registered here, due to lifecycle constraints related to {@code @Configuration}
        * class processing.
        * @param importingClassMetadata annotation metadata of the importing class
        * @param registry current bean definition registry
        */
       void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
    
    }
    
    @Configuration
    @Import({MyImportBeanDefinitionRegistrar.class})
    public class MainConfig3 {
    }
    
    public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            RootBeanDefinition beanDefinition = new RootBeanDefinition(Card.class);
            registry.registerBeanDefinition("myCard", beanDefinition);
        }
    }
    
    @Test
    public void mainConfig3Test() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig3.class);
        String[] definitionNames = context.getBeanDefinitionNames();
        for (int i = 0; i < definitionNames.length; i++) {
            System.out.println(definitionNames[i]);
        }
    }
    

    image-20211003141151094

总结

给容器中注册组件:

  1. 包扫描+组件标注注解(@Controller/@Service/@Respository/@Component)
  2. @Bean,导入第三方包里的组件
  3. @Import

生命周期

@Bean指定init和destroy方法

public class Plane {
    public Plane(){
        System.out.println("plane constructor");
    }

   public void initMethod() {
        System.out.println("plane initMethod");
    }

    public void destroyMethod() {
        System.out.println("plane destroyMethod");
    }

}
@Configuration
public class MainConfig4 {

    @Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
    public Plane plane(){
        return new Plane();
    }
}
@Test
public void mainConfig4Test() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig4.class);
    System.out.println("容器创建完成");
    context.close();
}

image-20211005162421090

InitializingBean接口&DisposableBean接口欧

public interface InitializingBean {

   /**
    * Invoked by the containing {@code BeanFactory} after it has set all bean properties
    * and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc.
    * <p>This method allows the bean instance to perform validation of its overall
    * configuration and final initialization when all bean properties have been set.
    * @throws Exception in the event of misconfiguration (such as failure to set an
    * essential property) or if initialization fails for any other reason
    */
    // 在所有属性设置完成后会调用
   void afterPropertiesSet() throws Exception;

}
public interface DisposableBean {

   /**
    * Invoked by the containing {@code BeanFactory} on destruction of a bean.
    * @throws Exception in case of shutdown errors. Exceptions will get logged
    * but not rethrown to allow other beans to release their resources as well.
    */
    // 在BeanFactory销毁时调用
   void destroy() throws Exception;

}
public class Plane implements InitializingBean, DisposableBean {
    public Plane(){
        System.out.println("plane constructor");
    }

    public void initMethod() {
        System.out.println("plane initMethod");
    }

    public void destroyMethod() {
        System.out.println("plane destroyMethod");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("plane afterPropertiesSet");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("plane destroy");
    }
}

image-20211005162644715

@PostConstruct&@PreDestroy

/**
 * The PostConstruct annotation is used on a method that needs to be executed
 * after dependency injection is done to perform any initialization. This
 * method MUST be invoked before the class is put into service. This
 * annotation MUST be supported on all classes that support dependency
 * injection. The method annotated with PostConstruct MUST be invoked even
 * if the class does not request any resources to be injected. Only one
 * method can be annotated with this annotation. The method on which the
 * PostConstruct annotation is applied MUST fulfill all of the following
 * criteria:
 * <p>
 * <ul>
 * <li>The method MUST NOT have any parameters except in the case of
 * interceptors in which case it takes an InvocationContext object as
 * defined by the Interceptors specification.</li>
 * <li>The method defined on an interceptor class MUST HAVE one of the
 * following signatures:
 * <p>
 * void &#060;METHOD&#062;(InvocationContext)
 * <p>
 * Object &#060;METHOD&#062;(InvocationContext) throws Exception
 * <p>
 * <i>Note: A PostConstruct interceptor method must not throw application
 * exceptions, but it may be declared to throw checked exceptions including
 * the java.lang.Exception if the same interceptor method interposes on
 * business or timeout methods in addition to lifecycle events. If a
 * PostConstruct interceptor method returns a value, it is ignored by
 * the container.</i>
 * </li>
 * <li>The method defined on a non-interceptor class MUST HAVE the
 * following signature:
 * <p>
 * void &#060;METHOD&#062;()
 * </li>
 * <li>The method on which PostConstruct is applied MAY be public, protected,
 * package private or private.</li>
 * <li>The method MUST NOT be static except for the application client.</li>
 * <li>The method MAY be final.</li>
 * <li>If the method throws an unchecked exception the class MUST NOT be put into
 * service except in the case of EJBs where the EJB can handle exceptions and
 * even recover from them.</li></ul>
 * @since Common Annotations 1.0
 * @see javax.annotation.PreDestroy
 * @see javax.annotation.Resource
 */
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
    // 在bean初始化完成并且依赖注入完成执行方法
}
/**
 * The PreDestroy annotation is used on methods as a callback notification to
 * signal that the instance is in the process of being removed by the
 * container. The method annotated with PreDestroy is typically used to
 * release resources that it has been holding. This annotation MUST be
 * supported by all container managed objects that support PostConstruct
 * except the application client container in Java EE 5. The method on which
 * the PreDestroy annotation is applied MUST fulfill all of the following
 * criteria:
 * <p>
 * <ul>
 * <li>The method MUST NOT have any parameters except in the case of
 * interceptors in which case it takes an InvocationContext object as
 * defined by the Interceptors specification.</li>
 * <li>The method defined on an interceptor class MUST HAVE one of the
 * following signatures:
 * <p>
 * void &#060;METHOD&#062;(InvocationContext)
 * <p>
 * Object &#060;METHOD&#062;(InvocationContext) throws Exception
 * <p>
 * <i>Note: A PreDestroy interceptor method must not throw application
 * exceptions, but it may be declared to throw checked exceptions including
 * the java.lang.Exception if the same interceptor method interposes on
 * business or timeout methods in addition to lifecycle events. If a
 * PreDestroy interceptor method returns a value, it is ignored by
 * the container.</i>
 * </li>
 * <li>The method defined on a non-interceptor class MUST HAVE the
 * following signature:
 * <p>
 * void &#060;METHOD&#062;()
 * </li>
 * <li>The method on which PreDestroy is applied MAY be public, protected,
 * package private or private.</li>
 * <li>The method MUST NOT be static.</li>
 * <li>The method MAY be final.</li>
 * <li>If the method throws an unchecked exception it is ignored except in the
 * case of EJBs where the EJB can handle exceptions.</li>
 * </ul>
 *
 * @see javax.annotation.PostConstruct
 * @see javax.annotation.Resource
 * @since Common Annotations 1.0
 */

@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PreDestroy {
    // 在容器移除bean之前回调通知
}
public class Plane implements InitializingBean, DisposableBean {
    public Plane(){
        System.out.println("plane constructor");
    }

    public void initMethod() {
        System.out.println("plane initMethod");
    }

    public void destroyMethod() {
        System.out.println("plane destroyMethod");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("plane afterPropertiesSet");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("plane destroy");
    }
    
    @PostConstruct
    public void post() {
        System.out.println("plane PostConstruct");
    }
    
    @PreDestroy
    public void preDestroy() {
        System.out.println("plane PreDestroy");
    }
}

image-20211005163302750

BeanPostProcessor接口

/**
 * Factory hook that allows for custom modification of new bean instances,
 * e.g. checking for marker interfaces or wrapping them with proxies.
 *
 * <p>ApplicationContexts can autodetect BeanPostProcessor beans in their
 * bean definitions and apply them to any beans subsequently created.
 * Plain bean factories allow for programmatic registration of post-processors,
 * applying to all beans created through this factory.
 *
 * <p>Typically, post-processors that populate beans via marker interfaces
 * or the like will implement {@link #postProcessBeforeInitialization},
 * while post-processors that wrap beans with proxies will normally
 * implement {@link #postProcessAfterInitialization}.
 *
 * @author Juergen Hoeller
 * @since 10.10.2003
 * @see InstantiationAwareBeanPostProcessor
 * @see DestructionAwareBeanPostProcessor
 * @see ConfigurableBeanFactory#addBeanPostProcessor
 * @see BeanFactoryPostProcessor
 */
// bean的后置处理器,在bean初始化前后进行一些操作
public interface BeanPostProcessor {

   /**
    * Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean
    * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
    * or a custom init-method). The bean will already be populated with property values.
    * The returned bean instance may be a wrapper around the original.
    * @param bean the new bean instance
    * @param beanName the name of the bean
    * @return the bean instance to use, either the original or a wrapped one;
    * if {@code null}, no subsequent BeanPostProcessors will be invoked
    * @throws org.springframework.beans.BeansException in case of errors
    * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
    */
    // 在已经创建的bean实例任何初始化方法调用前调用该方法
   Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

   /**
    * Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean
    * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
    * or a custom init-method). The bean will already be populated with property values.
    * The returned bean instance may be a wrapper around the original.
    * <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean
    * instance and the objects created by the FactoryBean (as of Spring 2.0). The
    * post-processor can decide whether to apply to either the FactoryBean or created
    * objects or both through corresponding {@code bean instanceof FactoryBean} checks.
    * <p>This callback will also be invoked after a short-circuiting triggered by a
    * {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
    * in contrast to all other BeanPostProcessor callbacks.
    * @param bean the new bean instance
    * @param beanName the name of the bean
    * @return the bean instance to use, either the original or a wrapped one;
    * if {@code null}, no subsequent BeanPostProcessors will be invoked
    * @throws org.springframework.beans.BeansException in case of errors
    * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
    * @see org.springframework.beans.factory.FactoryBean
    */
    // 在已经创建的bean实例任何初始化方法调用后调用该方法
   Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

}
@Component
public class MyPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization beanName:" + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization beanName:" + beanName);
        return bean;
    }
}
@Configuration
@ComponentScan("com.hjw.bean")
public class MainConfig4 {

    @Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
    public Plane plane(){
        return new Plane();
    }
}
image-20211005172103638
  • 原理

    打个断点看下大致的方法调用栈
    image-20211007161727379
    到mainConfig4Test,创建IOC容器
    在这里插入图片描述

    创建IOC容器
    在这里插入图片描述

    调用refresh方法,实例化所有剩下的单实例对象
    在这里插入图片描述
    实例化所有剩下的单例
    在这里插入图片描述

    创建bean>属性赋值>初始化
    在这里插入图片描述

    在初始化方法前后执行applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName)和applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName)
    在这里插入图片描述

    遍历所有的BeanPostProcessor,调用postProcessBeforeInitialization方法,如果返回null,不再执行后面的BeanPostProcessor
    在这里插入图片描述

  • BeanPostProcessor在Spring底层的使用

    BeanPostProcessor的实现类
    在这里插入图片描述

    • ApplicationContextAwareProcessor注入IOC容器

      在ApplicationContextAwareProcessor的postProcessBeforeInitialization方法中会调用invokeAwareInterfaces方法,在invokeAwareInterfaces方法中根据bean实现的接口注入相对应的资源

      image-20211010172939477

    • InitDestroyAnnotationBeanPostProcessor处理@PostConstruct和@PreDestroy注解的方法

      找到生命周期注解标注的方法,调用对应的方法

image-20211010180215268
image-20211010180614329

属性赋值

@Value

  1. 可以使用基本数值
  2. 可以使用SpEL:#{}
  3. 可以使用${}:取配置文件中的值(运行环境变量的值 )
    image-20211023181717560
    image-20211023181803706
    image-20211023181848181

自动装配

Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值。通过AutowiredAnnotationBeanPostProcessor实现自动装配。

@Autowired

  1. 默认优先按类型去容器中找对应的组件
  2. 如果找到多个相同类型的组件,再将属性名作为组件的id在容器中查找
  3. 可以使用@Qualifier指定需要装配的组件id,而不是属性名作为组件id
  4. 可以使用@Primary让Spring在自动装配的时候,默认使用首选的bean
@Configuration
@ComponentScan({"com.hjw.service"})
public class AutowriredConfig {

    @Bean("cardDao")
    public CardDao cardDao() {
        return new CardDao("cardDao");
    }

    @Primary
    @Bean("cardDao1")
    public CardDao cardDao1() {
        return new CardDao("cardDao1");
    }
}
@org.springframework.stereotype.Service
public class Service {

    @Autowired
    private CardDao cardDao;

    @Override
    public String toString() {
        return "Service{" +
                "cardDao=" + cardDao +
                '}';
    }
}
@Test
public void autowireTest() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AutowriredConfig.class);

    Service service = context.getBean(Service.class);
    System.out.println(service);

}

image-20211024172321265

@Resource(JSR250)&@Inject(JSR330)【java规范的注解】

  • @Resource

    可以和@Autowired一样实现自动装配,默认按组件名称装配。不支持@Primary,没有required属性

  • @Inject

    需要导入javax.inject包

    <dependency>
        <groupId>javax.inject</groupId>
        <artifactId>javax.inject</artifactId>
        <version>1</version>
    </dependency>
    

Aware接口

自定义组件想要使用Spring容器底层的一些组件(eg:ApplicationContext,BeanFactory…),可以通过实现xxxAware接口注入Spring底层组件。在创建对象的时候,会调用接口中定义的相关方法完成组件注入。对应的xxxAware接口通过xxxAwareProcesssor实现。

@Profile

根据环境注册bean。加了注解的bean,只有在这个环境被激活的时候才能注册到容器中。默认是default环境。

public class DataSource {
}
@Configuration
public class MainConfig5 {

    @Profile("default")
    @Bean("defaultDataSource")
    public DataSource defaultDataSource() {
        return new DataSource();
    }

    @Profile("test")
    @Bean("testDataSource")
    public DataSource testDataSource() {
        return new DataSource();
    }

    @Profile("dev")
    @Bean("devDataSource")
    public DataSource devDataSource() {
        return new DataSource();
    }
}
    /**
     * 切换环境:
     * 1.使用命令行参数,-Dspring.profiles.active=dev
     * 2.使用编码方式指定激活环境
     */
    @Test
    public void profileTest() {
//        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig5.class);
        // 创建容器
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        // 设置激活的环境
        context.getEnvironment().setActiveProfiles("dev","test");
        // 注册配置类
        context.register(MainConfig5.class);
        // 启动刷新容器
        context.refresh();

        String[] beanNamesForType = context.getBeanNamesForType(DataSource.class);
        for (String beanName : beanNamesForType) {
            System.out.println(beanName);
        }
        context.close();
    }

image-20211031112915014

中文文档

Spring中文文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值