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接口

 

posted @ 2019-05-18 15:27  *青锋*  阅读(1160)  评论(0编辑  收藏  举报