栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring注解-IOC

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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]);
        }
    }
}

  • 使用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 {
        @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());
    }
    

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

@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 {
}

自定义FilterType
public enum FilterType {

   
   ANNOTATION,

   
   ASSIGNABLE_TYPE,

   
   ASPECTJ,

   
   REGEX,

   
   CUSTOM

}

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

public class MyFilter implements TypeFilter {
    
    @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;
    }
}

@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);
    }
    

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

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

  • 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);
    }

打开注解时

@Conditional

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

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

   
   Class[] 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("容器创建完成");
}

@import
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@documented
public @interface 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]);
        }
    }
    

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

    public interface importSelector {
    
       
       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 {
    
       
       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]);
        }
    }
    

总结

给容器中注册组件:

  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();
}

InitializingBean接口&DisposableBean接口欧
public interface InitializingBean {

   
    // 在所有属性设置完成后会调用
   void afterPropertiesSet() throws Exception;

}
public interface DisposableBean {

   
    // 在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");
    }
}

@PostConstruct&@PreDestroy
@documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
    // 在bean初始化完成并且依赖注入完成执行方法
}

@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");
    }
}

BeanPostProcessor接口
// bean的后置处理器,在bean初始化前后进行一些操作
public interface BeanPostProcessor {

   
    // 在已经创建的bean实例任何初始化方法调用前调用该方法
   Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

   
    // 在已经创建的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();
    }
}
  • 原理

    打个断点看下大致的方法调用栈

    到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实现的接口注入相对应的资源

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

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


属性赋值 @Value
  1. 可以使用基本数值
  2. 可以使用SpEL:#{}
  3. 可以使用${}:取配置文件中的值(运行环境变量的值 )


自动装配

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);

}

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

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

  • @Inject

    需要导入javax.inject包

    
        javax.inject
        javax.inject
        1
    
    
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();
    }
}
    
    @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();
    }

中文文档

Spring中文文档

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/361359.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号