• spring(一):spring的基础以及组件


    spring简介

    spring是一种开源轻量级框架,是为了解决企业应用程序复杂性而创建的

    spring是企业应用开发的“一站式”框架,致力于为javaEE应用的各层(表现层、业务层、持久层)开发提供解决方案,而不仅仅是某一层的解决方案

    spring并不会代替原有的那些框架,而是以高度的开放性,与已存在的框架进行整合

    通过spring技术,不需要重复制造轮子,在已有较好解决方案的技术领域绝不重复实现。例如,对象持久化和OR映射,spring只对现有的JDBC、Hibernate等技术提供支持,使之更加便于使用,不需要做重复的实现


    spring组成结构

    spring core:spring核心,是框架最基础的部分,提供spring IOC和依赖注入的功能

    spring context:spring上下文容器,是对BeanFactory功能增强的一个子接口

    spring web:spring的web模块,提供了对web应用开发的支持

    spring mvc:针对web应用mvc思想的实现

    spring orm:支持对流行ORM框架的整合,mybatis、hibernate

    spring dao:提供对JDBC的抽象,简化JDBC编码

    spring aop:面向切面编程,提供了与AOP联盟兼容的编程实现


    spring常用组件

    @Configuration

    在类上使用,指定该类为配置类,相当于配置文件

    @Bean

    在方法上使用,向容器注册一个bean,返回值是bean的类型,bean的id默认是方法名,可以设置bean的id @Bean(name)

    /**
     * 配置类,相当于配置文件的作用
     * @author qf
     * @create 2019-05-20 9:55
     */
    @Configuration
    public class MainConfig {
        /**
         * 向容器注册一个bean,返回类型为bean的类型
         * 默认方法名是bean的id名,可以通过配置@Bean(yoursName)设置id
         * @return
         */
        @Bean("wxf")
        public Person person(){
            return new Person("wxf",19);
        }
    }
    

    AnnotationConfigApplicationContext

    根据注解配置类获取spring的IOC容器

    @Test
    public void testConfig(){
    	/**
    	 * 注解配置来获取spring IOC容器
    	 */
    	ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
    	Person person = (Person) context.getBean("wxf");
    	System.out.println(person);
    }
    

    @ComponentScan

    设置扫描规则,指定要扫描的包,扫描带有@Controller、@Service、@Repository以及@Component注解的类

    value:指定要扫描的包

    excludeFilters:Filters[],指定扫描的时候按照什么规则排除哪些组件  

    includeFilters:Filters[],指定扫描时按照什么规则只包含哪些组件

      扫描规则

        FilterType.ANNOTATION:按照注解

        FilterType.ASSIGNABLE_TYPE:按照给定的类型;比如按BookService类型

        FilterType.ASPECTJ:使用ASPECTJ表达式

        FilterType.REGEX:使用正则指定

        FilterType.CUSTOM:使用自定义规则,自已写类,实现TypeFilter接口

      classes:

        Controller.class:表示扫描的是使用了@Controller注解的类

        Service.class、Repository.class、Component.class

    useDefaultFilters:默认true,扫描所有组件;false:使用自定义扫描范围  

    @Configuration
    @ComponentScan(value = "com.enjoy.study.cap2",excludeFilters={
            @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
    },includeFilters = {
            @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Service.class})
    },useDefaultFilters = false)
    public class MainConfig {
        @Bean()
        public Person person(){
            return new Person("wxf",19);
        }
    }

    案例:测试自定义规则使用

    1. 自定义过滤规则类

    public class MyTypeFilter implements TypeFilter {
        /**
         *
         * @param metadataReader:读取到的当前正在扫描的类的信息
         * @param metadataReaderFactory:可以获取其它任何类的信息的工厂
         * @return
         * @throws IOException
         */
        @Override
        public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
            //获取当前类的注解信息
            AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
            //获取当前正在扫描的类的信息
            ClassMetadata classMetadata = metadataReader.getClassMetadata();
            //获取当前类资源(类路径)
            Resource resource = metadataReader.getResource();
            //获取当前类的类名
            String className = classMetadata.getClassName();
    
            if(className != null && className.contains("Dao")){
                return true;
            }
            return false;
        }
    }
    

    2. 在配置类中使用

    com.enjoy.study.cap2包下

      

    @Configuration
    @ComponentScan(value = "com.enjoy.study.cap2",includeFilters = {
            @ComponentScan.Filter(type = FilterType.CUSTOM,classes = {MyTypeFilter.class})
    },useDefaultFilters = false)
    public class MainConfig {
        @Bean()
        public Person person(){
            return new Person("wxf",19);
        }
    }
    

    3. 测试方法,打印spring的IOC容器中的所有对象

    @Test
    public void testConfig2(){
    	/**
    	 * 注解配置来获取spring IOC容器
    	 */
    	ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
    	//获取类名
    	String[] names = context.getBeanDefinitionNames();
    	for (String name : names) {
    		System.out.println(name);
    	}
    }

     4. 打印结果

    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.annotation.internalRequiredAnnotationProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    mainConfig
    userDao
    person

    @Scope

    spring中默认的bean是单例的,@Scope(value)可以设置bean实例的不同创建方式

    singleton:默认方式,单实例,IOC容器启动时调用方法创建对象并放入IOC容器中,以后每次获取的就是从容器中拿到的同一个实例对象

    prototype:多实例,IOC容器启动时并不会调用方法创建对象,以后每次获取时都调用方法创建一个对象

    request:主要针对web应用,一个请求创建一个对象

    session:主要针对web应用,一次session会话创建一个对象

    @Configuration
    public class MainConfig {
    
        @Bean
        @Scope(value = "prototype")
        public Person person(){
            return new Person();
        }
    }
    
    @Test
    public void getBean(){
    	ApplicationContext context = new AnnotationConfigApplicationContext(com.enjoy.study.cap3.MainConfig.class);
    	Object person1 = context.getBean("person");
    	Object person2 = context.getBean("person");
    	System.out.println(person1 == person2);
    }
    

    没使用@Scope注解之前返回true,因为默认使用singleton模式;添加@Scope("prototype")后返回false

    @Lazy

    懒加载

    默认情况下,启动容器是创建对象;配置懒加载后,启动容器时不创建对象,在第一次使用bean时创建对象

    @Configuration
    public class MainConfig {
    
        @Bean
        @Lazy
        public Person person(){
            System.out.println("IOC容器创建对象");
            return new Person("qf",21);
        }
    }
    
    public class LazyTest {
        /**
         * 测试IOC容器创建bean实例对象的时机
         */
        @Test
        public void lazyT(){
            ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
            System.out.println("IOC容器启动完成");
    
            context.getBean("person");
        }
    }
    /* 注释@Lazy */
    IOC容器创建对象
    IOC容器启动完成
    
    /* 不注释@Lazy */
    IOC容器启动完成
    IOC容器创建对象
    

    使用懒加载时,第一次context.getBean时才会创建实例对象


     @Conditional

    条件注册bean

    IOC容器注册bean时,使用@Conditional(MyCondition.class),使得满足自定义条件类MyCondition的bean才会被注册到IOC容器中

    MyCondition类必须实现Condition接口,实现其中的match方法

     测试案例:根据不同操作系统,Windows系统时wxf注入IOC,linux系统下qf注入IOC容器

    条件类

    public class MyWinCondition implements Condition {
        /**
         *
         * @param conditionContext :判断条件能使用的上下文
         * @param annotatedTypeMetadata :注释信息
         * @return
         */
        @Override
        public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
            //获取IOC容器使用的BeanFactory
            ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
            //获取类加载器
            ClassLoader classLoader = conditionContext.getClassLoader();
            //获取当前环境信息
            Environment environment = conditionContext.getEnvironment();
            //获取bean定义的注册类
            BeanDefinitionRegistry registry = conditionContext.getRegistry();
    
            //获取当前环境的操作系统名
            String osName = environment.getProperty("os.name");
            if(osName != null && osName.contains("Windows")){
                return true;
            }
            return false;
        }
    }

    public class MyLinuxCondition implements Condition {
        /**
         *
         * @param conditionContext :判断条件能使用的上下文
         * @param annotatedTypeMetadata :注释信息
         * @return
         */
        @Override
        public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
            //获取当前环境信息
            Environment environment = conditionContext.getEnvironment();
            //获取当前环境的操作系统名
            String osName = environment.getProperty("os.name");
            if(osName != null && osName.contains("Linux")){
                return true;
            }
            return false;
        }
    }
    

    配置类

    @Configuration
    public class Cap5MainConfig {
    
        @Bean("person")
        public Person person(){
            System.out.println("person 被注册到IOC容器");
            return new Person();
        }
    
        @Conditional(MyWinCondition.class)
        @Bean("wxf")
        public Person wxf(){
            System.out.println("wxf 被注册到IOC容器");
            return new Person();
        }
    
        @Conditional(MyLinuxCondition.class)
        @Bean("qf")
        public Person qf(){
            System.out.println("qf 被注册到IOC容器");
            return new Person();
        }
    
    }
    

    测试类

    public class Cap5Test {
    
        @Test
        public void testGetBean(){
            ApplicationContext context = new AnnotationConfigApplicationContext(Cap5MainConfig.class);
            String[] names = context.getBeanDefinitionNames();
            for (String name : names) {
                System.out.println(name);
            }
        }
    }
    

    打印结果

    person 被注册到IOC容器
    wxf 被注册到IOC容器
    org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    org.springframework.context.annotation.internalRequiredAnnotationProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessor
    org.springframework.context.event.internalEventListenerProcessor
    org.springframework.context.event.internalEventListenerFactory
    cap5MainConfig
    person
    wxf
    

    当前系统是Windows,所以qf没被注册到IOC容器中


     @Import

    注册bean

    在类上使用的注解

    使用:

    1. @Import({Person.class})或者@Import({Person.class,User.class}):容器中会自动注册这个bean,id是这个bean的全路径名
    2. @Import+ImportSelector接口:ImportSelector接口返回需要导入的组件的全类名数组
    3. @Import+ImportBeanDefinitionRegistrar接口:自定义注册bean到容器中

    测试

    测试类

    public class Cap6Test {
        @Test
        public void importTest(){
            ApplicationContext context = new AnnotationConfigApplicationContext(Cap6MainConfig.class);
            String[] names = context.getBeanDefinitionNames();
            for (String name : names) {
                System.out.println("name = " + name);
            }
        }
    1. @Import({Person.class})或者@Import({Person.class,User.class})
      配置类
      @Configuration
      @Import({User.class})
      public class Cap6MainConfig {
      
      }

      结果
      name = org.springframework.context.annotation.internalConfigurationAnnotationProcessor
      name = org.springframework.context.annotation.internalAutowiredAnnotationProcessor
      name = org.springframework.context.annotation.internalRequiredAnnotationProcessor
      name = org.springframework.context.annotation.internalCommonAnnotationProcessor
      name = org.springframework.context.event.internalEventListenerProcessor
      name = org.springframework.context.event.internalEventListenerFactory
      name = cap6MainConfig
      name = com.enjoy.study.cap6.pojo.User
    2. @Import+ImportSelector接口
      配置类
      @Configuration
      @Import({User.class, MyImportSelector.class})
      public class Cap6MainConfig {
      
      }

      自定义导入选择器
      /**
       * 自定义逻辑返回要导入容器的组件
       * @author qf
       * @create 2019-05-21 13:57
       */
      public class MyImportSelector implements ImportSelector {
          /**
           *
           * @param annotationMetadata 当前标注@Import注解的类的所有注解信息,不仅仅能获取到@Import注解,可以获取该类的所有注解
           * @return
           */
          @Override
          public String[] selectImports(AnnotationMetadata annotationMetadata) {
              /**
               * 注意:不要返回null,返回null,会报空指针
               */
              return new String[]{"com.enjoy.study.cap6.pojo.Student","com.enjoy.study.cap6.pojo.Teacher"};
          }
      }

      结果
      name = org.springframework.context.annotation.internalConfigurationAnnotationProcessor
      name = org.springframework.context.annotation.internalAutowiredAnnotationProcessor
      name = org.springframework.context.annotation.internalRequiredAnnotationProcessor
      name = org.springframework.context.annotation.internalCommonAnnotationProcessor
      name = org.springframework.context.event.internalEventListenerProcessor
      name = org.springframework.context.event.internalEventListenerFactory
      name = cap6MainConfig
      name = com.enjoy.study.cap6.pojo.User
      name = com.enjoy.study.cap6.pojo.Student
      name = com.enjoy.study.cap6.pojo.Teacher 
    3. @Import+ImportBeanDefinitionRegistrar接口
      /**
       * 自定义bean注册类
       * @author qf
       * @create 2019-05-21 14:09
       */
      public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
          /**
           *
           * @param annotationMetadata:当前类的注解信息
           * @param beanDefinitionRegistry:BeanDefinition注册类,把所有需要添加到容器的bean,
           *              调用BeanDefinitionRegistry的registerBeanDefinitions方法自定义手工注册进来
           */
          @Override
          public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
              //容器中是否存在Student
              boolean definitionStu = beanDefinitionRegistry.containsBeanDefinition("com.enjoy.study.cap6.pojo.Student");
              //容器中是否存在Teacher
              boolean definitionTea = beanDefinitionRegistry.containsBeanDefinition("com.enjoy.study.cap6.pojo.Teacher");
      
              //如果容器中存在Student和Teacher
              if(definitionStu && definitionTea){
                  RootBeanDefinition beanDefinition = new RootBeanDefinition(User.class);
                  /**
                   * 第一个参数:自定义bean的名,不一定是全路径
                   * 第二个参数:beanDefinition,bean的定义信息(类型,作用域等)
                   */
                  beanDefinitionRegistry.registerBeanDefinition("user",beanDefinition);
              }
          }
      }

      配置类
      @Configuration
      @Import({MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})
      public class Cap6MainConfig {
      
      }

      结果
      name = org.springframework.context.annotation.internalConfigurationAnnotationProcessor
      name = org.springframework.context.annotation.internalAutowiredAnnotationProcessor
      name = org.springframework.context.annotation.internalRequiredAnnotationProcessor
      name = org.springframework.context.annotation.internalCommonAnnotationProcessor
      name = org.springframework.context.event.internalEventListenerProcessor
      name = org.springframework.context.event.internalEventListenerFactory
      name = cap6MainConfig
      name = com.enjoy.study.cap6.pojo.Student
      name = com.enjoy.study.cap6.pojo.Teacher
      name = user  

    FactoryBean

    主要功能是将bean注册到容器中

    public interface FactoryBean<T> {
        T getObject() throws Exception;
    
        Class<?> getObjectType();
    
        boolean isSingleton();
    }
    
    • getObject():容器调用getObject方法返回对象,并将该对象放入容器中
    • getObjectType():返回对象类型
    • isSingleton():是否是单例进行控制

    测试一

    自定义FactoryBean
    public class MyFactoryBean implements FactoryBean<User> {
        @Override
        public User getObject() throws Exception {
            return new User();
        }
    
        @Override
        public Class<?> getObjectType() {
            return User.class;
        }
    
        @Override
        public boolean isSingleton() {
            return false;
        }
    }

    配置类
    @Configuration
    public class Cap6MainConfig {
    
        @Bean
        public MyFactoryBean user(){
            return new MyFactoryBean();
        }
    }

    结果
    name = org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    name = org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    name = org.springframework.context.annotation.internalRequiredAnnotationProcessor
    name = org.springframework.context.annotation.internalCommonAnnotationProcessor
    name = org.springframework.context.event.internalEventListenerProcessor
    name = org.springframework.context.event.internalEventListenerFactory
    name = cap6MainConfig
    name = user
    

    测试二

    @Test
    public void factoryBean() throws Exception {
    	ApplicationContext context = new AnnotationConfigApplicationContext(Cap6MainConfig.class);
    	//获取自定义FactoryBean本身
    	Object bean = context.getBean("&user");
    	System.out.println(bean.getClass());
    	System.out.println("--------------");
    	//获取通过自定义FactoryBean注册到容器中的bean对象
    	bean = context.getBean("user");
    	System.out.println(bean.getClass());
    }

    结果
    class com.enjoy.study.cap6.MyFactoryBean
    --------------
    class com.enjoy.study.cap6.pojo.User

    spring中注册bean的方式总结:

    1. 包扫描(@ComponentScan)+组件标注注解(@Controller、@Service、@Repository、@Component)
    2. @Bean【导入第三方类或者包的组件,比如Person是第三方提供的类,使用@Bean注册到IOC容器】
    3. @Import【快速给容器导入一个组件】
    4. 实现FactoryBean接口

  • 相关阅读:
    HDU 跑跑卡丁车
    螺旋模型
    原型模型
    CSS匹配规则参考
    索引调优
    动态加载外部css或js文件
    des算法的C#实现
    @@RowCount和“SET NOCOUNT ON”在触发器中使用的先后顺序引起的问题
    WebService生成XML文档时出错。不应是类型XXXX。使用XmlInclude或SoapInclude属性静态指定非已知的类型。
    Sql获取星期几的方法
  • 原文地址:https://www.cnblogs.com/qf123/p/10885897.html
Copyright © 2020-2023  润新知