Spring学习笔记1——Spring基础及组件使用

Spring简介

  1. Spring是一种开源轻量级框架,是为了解决企业应用程序开发复杂性而创建的,Spring致力于解决Java EE的各层解决方案,而不仅仅于某一层的方案。

  2. 可以说Spring是企业应用开发的“一站式”选择,Spring贯穿于表现层、业务层、持久层,然而Spring并不想取代那些已经有的框架,而是以高度的开放性,与这些已有的框架进行整合

  3. Spring是一个全面的解决方案,它坚持一个原则:不重新造轮子。已经有较好解决方案的领域,Spring绝不重复性实现,比如:对象持久化和OR映射,Spring只对现有的JDBCHibernate等技术提供支持,使之更容易使用,而不做重复的实现。Spring框架有很多特性,这些特性由7个定义良好的模块构成:

    • Spring Core:即,Spring核心,它是框架最基础的部分,提供IOC和依赖注入特性。
    • Spring Context:即,Spring上下文容器,它是BeanFactory功能加强的一个子接口。
    • Spring Web:它提供Web应用开发的支持。
    • Spring MVC:它针对Web应用中MVC思想的实现。
    • Spring DAO:提供对JDBC抽象层,简化了JDBC编码,同时,编码更具有健壮性。
    • Spring ORM:它支持用于流行的ORM框架的整合,比如:Spring+HibernateSpring+iBatisSpring+JDO的整合等等。
    • Spring AOPAOP即,面向切面编程,它提供了与AOP联盟兼容的编程实现。
  4. Spring常用组件:
    在这里插入图片描述

xml配置与@Configuration注解配置

  1. xml配置方式:

    beans.xml主要代码如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="..." ...>
        <!-- Person类定义在此省略 -->
    	<bean id ="person" class="com.study.spring.Person">
            <property name="name" value="yhl"></property>
            <property name="age" value="18"></property>
        </bean>
    </beans>
    

    测试类主要代码如下:

    public class MainTest1{
        public static void main(String args[]){
            // 把beans.xml中的类加载到容器中
            ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
            // 从容器中获取bean
            Person person = (Person) app.getBean("person");
            System.out.println(person);
        }
    }
    
  2. 注解配置方式:

    配置类主要代码如下:

    // 配置类,相当于配置文件
    @Configuration
    public class MainConfig{
        // 给容器中注册一个bean,类型为返回值的类型
        @Bean
        public Person person(){
            return new Person("yhl",19);
        }
    }
    

    测试类主要代码如下:

    public class MainTest2{
        public static void main(String args[]){
           ApplicationContext app = new AnnotationConfigApplicationContext(MainConfig.class);
            // 从容器中获取bean
            Person person = (Person) app.getBean("person");
            System.out.println(person);
        }
    }
    
  3. @Configurationbeans.xml作用一样,@Configuration更简单、灵活

@ComponentScan扫描规则

  1. 可以定制包扫描时的过滤规则,比如,以下代码会扫描出@ControllerBookService

    @Configuration
    @ComponentScan(value="com.study.spring",includeFilters={
        @Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
        @Filter(type=FilterType.ASSIGNABLE_TYPE,classes={BookService.class})
    },useDefaultFilters=false) 
    public class MainConfig2 {
        // 给容器中注册一个bean,类型为返回值的类型
        @Bean
        public Person person01(){
            return new Person("yhl",19);
        }
    }
    
  2. @ComponentScan注解的属性:

    • value:指定要扫描的包。
    • excludeFilters = Filter[]:指定扫描的时候按照什么规则排除哪些组件。
    • includeFilters = Filter[]:指定扫描的时候只需要包含哪些组件。
    • useDefaultFilters = false:默认是true扫描所有组件,要改成false,才能使用自定义扫描范围。
  3. @Filter的扫描规则如下:

    • FilterType.ANNOTATION:按照注解,比如@Controller@Service@Repository@Component注解。
    • FilterType.ASSIGNABLE_TYPE:按照给定的类型,比如BookService类型。
    • FilterType.ASPECTJ:使用ASPECTJ表达式。
    • FilterType.REGEX:使用正则指定。
    • FilterType.CUSTOM:使用自定义规则,自已写类,实现TypeFilter接口。
  4. 自定义规则示例:

    public class YhlTypeFilter implements TypeFilter{
        
        private ClassMetadata classMetadata;
        
        /*
         * MetadataReader:读取到当前正在扫描类的信息
         * MetadataReaderFactory:可以获取到其他任何类的信息
         */
        @Override
        public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException{
            // 获取当前类注解的信息
            AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
            // 获取当前正在扫描的类信息
            classMetadata = metadataReader.getClassMetadata();
            // 获取当前类资源(类的路径)
            Resource resource = meatadataReader.getResource();
            
            String className = classMetadata.getClassName();
            System.out.println("--->" + className);
            
            // 当类包含er字符,则匹配成功,返回true
            if(className.contains("er")){
                return true;
            }
            return false;
        }
    }
    
    @Configuration
    @ComponentScan(value="com.study.spring",includeFilters={
        @Filter(type=FilterType.CUSTOM,classes={YhlTypeFilter.class})
    },useDefaultFilters=false) 
    public class MainConfig2 {
        // 给容器中注册一个bean,类型为返回值的类型
        @Bean
        public Person person(){
            return new Person("yhl",19);
        }
    }
    

@Scope扫描规则

  1. @Scope注解的值:

    • prototype:多实例,IOC容器启动的时候并不会取调用方法创建对象,而是每次获取的时候才会调用方法创建对象。
    • singleton:单实例(默认),IOC容器启动的时候会调用方法创建对象并放到IOC容器中,以后每次获取的就是直接从容器中拿的同一个bean
    • request:主要针对web应用,递交一次请求创建一个实例。
    • session:同一个session创建一个实例。
  2. 没加@Scope之前, 默认的bean是单实例的。

  3. 比如,以下代码指定bean为多实例:

    @Configuration
    public class MainConfig3{
        // 给容器中注册一个bean,类型为返回值的类型,默认是单实例
        @Scope("prototype")
        @Bean
        public Person person(){
            return new Person("yhl",19);
        }
    }
    

@Lazy懒加载

  1. 主要针对单实例bean(单实例bean默认在容器启动的时候创建对象),使用懒加载后,容器启动的时候不创建对象,仅当第一次使用(获取)bean的时候才创建并初始化。

  2. 示例如下:

    @Configuration
    public class MainConfig4{
        // 给容器中注册一个bean,类型为返回值的类型,默认是单实例
        @Lazy
        @Bean
        public Person person(){
            return new Person("yhl",19);
        }
    }
    

@Conditional条件注册bean

  1. 当引入@Conditional时, 容器可以选择性的注册bean。比如,当操作系统为WINDOWS时,注册yhl1实例; 当操作系统为LINUX时, 注册yhl2实例:

    // 配置类
    @Configuration
    public class MainConfig5{
        
        @Conditional({WinCondition.class})
        @Bean("yhl1")
        public Person yhl1(){
            return new Person("yhl1",19);
        }
        
        @Conditional({LinuxCondition.class})
        @Bean("yhl2")
        public Person yhl2(){
            return new Person("yhl2",20);
        }
    }
    
    // 条件类,必须得实现Spring提供的Confition接口
    public class WinCondition implements Condition{
    	
    	/*
    	 * ConditionContext: 判断条件能使用的上下文(环境)
    	 * AnnotatedTypeMetadata: 注释信息
    	 */
    	@Override
    	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            // 能获取到IOC容器正在使用的beanFactory
    		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
            // 获取当前环境变量(包括操作系统时WIN还是LINUX)
    		Environment environment = context.getEnvironment();
    		String os_name = environment.getProperty("os.name");
    		if(os_name.contains("Windows")){
    			return true;
    		}
    		return false;
    	}
    }
    
    // 条件类,必须得实现Spring提供的Confition接口
    public class LinCondition implements Condition{
    
    	/*
    	 * ConditionContext: 判断条件能使用的上下文(环境)
    	 * AnnotatedTypeMetadata: 注释信息
    	 */
    	@Override
    	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    		// 能获取到IOC容器正在使用的beanFactory
    		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    		// 获取当前环境变量(包括操作系统时WIN还是LINUX)
    		Environment environment = context.getEnvironment();
    		String os_name = environment.getProperty("os.name");
    		if(os_name.contains("linux")){
    			return true;
    		}
    		return false;
    	}
    }
    
  2. FactoryBeanBeanFactory的区别:可以把Java实例bean通过FactoryBean注入到容器中;BeanFactory从容器中获取实例化后的bean

@Import注册bean

  1. 给容器注册组件的方式

    • @Bean:导入第三方的类或包的组件,比如Person为第三方的类,需要在IOC容器中使用。
    • 包扫描+组件的标注注解@ComponentScan@Controller@Service@Repository@Component):一般是针对自己写的类,使用这个。
    • @Import:快速给容器导入一个组件。@Bean有点简单。
      • @Import(要导入到容器中的组件):容器会自动注册这个组件,beanid为全类名
      • ImportSelector:是一个接口,返回需要导入到容器的组件的全类名数组
      • ImportBeanDefinitionRegistrar:可以手动添加组件到IOC容器,所有bean的注册可以使用BeanDefinitionRegistry,写YhlImportBeanDefinitionRegistrar实现ImportBeanDefinitionRegistrar接口即可
    • 使用Spring提供的FactoryBean(工厂Bean)进行注册:容器调用getObject()返回对象,把对象放到容器中;getObjectType()返回对象类型;isSingleton()是否单例进行控制。新建YhlFactoryBean实现FactoryBean,在config里新建yhlFactoryBean()方法。
  2. 使用@Importdogcatbean注册到容器中:

    @Configuration
    // 导入组件,ID默认是组件的全类名
    @Import(value = {Dog.class,Cat.class})
    public class MainConfig6 {
    
        // 容器启动时初始化person的bean实例
        @Bean
    	public Person person(){
            return new Person("yhl",19);
        }
    }
    
  3. ImportSelector可以批量导入组件的全类名数组,自定义逻辑返回需要导入的组件:

    public class YhlImportSelector implements ImportSelector{
    	@Override
    	public String[] selectImports(AnnotationMetadata importingClassMetadata){
    		// 返回全类名的bean
    		return new String[]{"com.study.spring.Fish","com.study.spring.Tiger"};
    	}
    }
    
    @Configuration
    @Import(value = {Dog.class,Cat.class,YhlImportSelector.class})
    public class MainConfig7 {
    
        // 容器启动时初始化person的bean实例
        @Bean
    	public Person person(){
            return new Person("yhl",19);
        }
    }
    
  4. 通过ImportBeanDefinitionRegistrar自定义注册,向容器中注册bean

    public class YhlImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    
    	/*
    	 * AnnotationMetadata:当前类的注解信息
    	 * BeanDefinitionRegistry:BeanDefinition注册类,把所有需要添加到容器中的bean加入
    	 * 调用BeanDefinitionRegistry.registerBeanDefinition自定义手工注册进来
    	 */
    	@Override
    	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    		boolean bean1 = registry.containsBeanDefinition("com.study.spring.Dog");
    		boolean bean2 = registry.containsBeanDefinition("com.study.spring.Cat");
    		// 如果Dog和Cat同时存在于IOC容器中,那么创建Pig类,加入到容器
    		if(bean1 && bean2){
                // 以前的bean都是全类名,现在自定义bean名
                // 对于要注册的bean,需要给bean进行封装
    			RootBeanDefinition beanDefinition = new RootBeanDefinition(Pig.class);
                // 注册一个bean,bean名为pig
    			registry.registerBeanDefinition("pig", beanDefinition);
    		}
    	}
    
    }
    
    @Configuration
    @Import(value = {Dog.class,Cat.class,YhlImportSelector.class,YhlImportBeanDefinitionRegistrar.class})
    public class MainConfig8 {
    
        // 容器启动时初始化person的bean实例
        @Bean
    	public Person person(){
            return new Person("yhl",19);
        }
    }
    
  5. 通过实现FactoryBean接口方式来加载bean

    public class YhlFactoryBean implements FactoryBean<Monkey>{
    
    	@Override
    	public Monkey getObject() throws Exception {
    		return new Monkey();
    	}
    
    	@Override
    	public Class<?> getObjectType() {
    		return Monkey.class;
    	}
    	
    	@Override
    	public boolean isSingleton() {
    		return true;
    	}
    }
    
    @Configuration
    public class MainConfig9 {
    
        @Bean
    	public YhlFactoryBean yhlFactoryBean(){
    		return new YhlFactoryBean();
    	}
    }
    

    默认获取到的是工厂bean调用getObject创建的对象,要获取工厂bean本身,需要在id前加个yhlFactoryBean

bean生命周期

  1. bean的生命周期是指**bean创建-----初始化----销毁**的过程,是由容器进行管理的。

  2. 可以自定义 bean初始化和销毁方法:容器在bean进行到当前生命周期的时候, 来调用自定义的初始化和销毁方法,有3种方式:

    • 指定初始化和销毁方法:

      • beans.xml中可以指定init-methoddestory-mothod

      • 用注释的话,在配置类里通过@Bean(initMethod="init",destroyMethod="destroy")指定。

        @Bean(initMethod="init", destroyMethod="destory")
        public Bike bike(){
            return new Bike();
        }
        

        单实例:当容器关闭的时候,会调用destroy消耗。

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

    • Bean实现InitializingBeanDisposableBean接口:

      • InitializingBean(定义初始化逻辑):afterPropertiesSet()方法:当beanFactory创建好对象,且把bean所有属性设置好之后,会调这个方法,相当于初始化方法。
      • DisposableBean(定义销毁逻辑):destory()方法,当bean销毁时,会把单实例bean进行销毁。
      @Component
      public class Train implements InitializingBean, DisposableBean{
      
      	public Train(){
      		System.out.println("Train......constructor............");
      	}
      	// 当bean销毁时,调用此方法
      	@Override
      	public void destroy() throws Exception {
      		System.out.println("Train......destory......");
      		//logger.error
      	}
      	// 当bean属性赋值和初始化完成时调用
      	@Override
      	public void afterPropertiesSet() throws Exception {
      		System.out.println("Train.......afterPropertiesSet()...");
      		
      	}
      
      }
      
    • 使用JSR250规则定义的(java规范)两个注解来实现:

      • @PostConstruct:在bean创建完成,且赋值完成后进行初始化,属于JDK规范的注解。
      • @PreDestroy:在bean将被移除之前进行通知,在容器销毁之前进行清理工作。
      @Component
      public class Jeep {
      	public Jeep(){
      		System.out.println("Jeep.....constructor........");
      	}
      	@PostConstruct
      	public void init(){
      		System.out.println("Jeep.....@PostConstruct........");
      	}
      	
      	@PreDestroy
      	public void destory(){
      		System.out.println("Jeep.....@PreDestroy......");
      	}
      }
      
  3. BeanPostProcessor类(interface)是bean的后置处理器,负责在初始化方法前后进行一些处理工作:

    • postProcessBeforeInitialization():在初始化之前进行后置处理工作(在init-method之前)。在任何初始化方法调用之前调用此方法(比如在InitializingBeanafterPropertiesSet初始化之前,或自定义init-method调用之前使用)。
    • postProcessAfterInitialization():在初始化之后进行后置处理工作,比如在InitializingBeanafterPropertiesSet()之后。
    /*
     * 后置处理器:初始化前后进行处理工作
     * 将后置处理器加入到容器中
     */
    @Component
    public class YhlBeanPostProcessor implements BeanPostProcessor{
        
    	@Override
    	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    		System.out.println("postProcessBeforeInitialization...."+beanName+"..."+bean);
    		// 返回一个对象(传过来的对象),也可包装好再返回
            return bean;
    	}
        
    	@Override
    	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    		System.out.println("postProcessAfterInitialization...."+beanName+"..."+bean);
    		return bean;
    	}
    }
    
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值