zoukankan      html  css  js  c++  java
  • 全注解下的IOC

    全注解下的IOC

        spring的两个核心理念,控制反转(Inversion of Control,IOC)和面向切面编程(Aspect Oriented Programming ,AOP)
    

    ​ 通常情况下使用new来创建对象,而spring通过描述创建对象。spring boot不建议使用XML,而是通过注解的方式来创建对象,由于对象之间存在着依赖关系,所以spring 还提供了依赖注入的功能,来管理各个对象之间的关系

    ​ spring把每一个需要其管理的队形称之为Bean,spring为管理这些Bean的容器,所以成为IOC容器

    一、IOC 容器

    ​ 所有的IOC容器都需要实现BeanFactory

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package org.springframework.beans.factory;
    
    import org.springframework.beans.BeansException;
    import org.springframework.core.ResolvableType;
    import org.springframework.lang.Nullable;
    
    public interface BeanFactory {
        String FACTORY_BEAN_PREFIX = "&";
    	// 多个 getBean 方法
        Object getBean(String var1) throws BeansException;
    
        <T> T getBean(String var1, Class<T> var2) throws BeansException;
    
        Object getBean(String var1, Object... var2) throws BeansException;
    
        <T> T getBean(Class<T> var1) throws BeansException;
    
        <T> T getBean(Class<T> var1, Object... var2) throws BeansException;
    
        <T> ObjectProvider<T> getBeanProvider(Class<T> var1);
    
        <T> ObjectProvider<T> getBeanProvider(ResolvableType var1);
    
        // 是否包含bean
        boolean containsBean(String var1);
    	// bean是否单例
        boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
    	// bean是否原型
        boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;
    	//bean是否类型匹配
        boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;
    
        boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;
    	//获取bean的类型
        @Nullable
        Class<?> getType(String var1) throws NoSuchBeanDefinitionException;
    	//获取bean的别名
        String[] getAliases(String var1);
    }
    
    

    ​ 多个getBean方法可以从IOC容器中获取到bean ,它允许我们可以按类型和名称和获取bean

    ​ isSingleton和isPrototype功能相反,判断bean是单例还是原型

    ​ 在BeanFactory的基础上有高级一点的接口ApplicationContext,我们使用的

    大部分的IOC容器都是ApplicationContext的实现类

    ​ ApplicationContext在BeanFactory 的基础上,扩展了消息国际化接口( MessageSource )、环境可配置接口 ( EnvironmentCapable )、应用事件发布接口( ApplicationEventPublisher ) 和资源模式解析接口( ResourcePatternResolver )

    ​ 在全注解的模式下我么使用AnnotationConfigApplicationContext 来作为IOC容器

    ​ 首先使用@Configuration和@Bean来构建配置类,

    • @Configuration 代表这是一个 Java 配置类 , Spring 的容器会根据它来生成 IoC 容器去装配 Bean;
    • @Bean 代表将 方法返回的 POJO 装配到 IoC 容器中,而其属性 name 定义这个 Bean 的名称,如果没有配置它,则将方法名称方法名作为 Bean 的名称保存到 Spring IoC 容器中

    ​ 如:

    user.java

    package com.springboot.chapter3.pojo
    
    public class User{
    	private Long id;
    	private String userName;
    	private String note
    	
    	/** setter and getter**/
    }
    

    AppConfig.java

    package com.springboot.chapter3.config;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import com.springboot.chapter3.pojo.User;
    
    
    @Configuration
    public class AppConfig {
        
    	@Bean(name ="user")
        public User initUser () {
        	User user= new User();
        	user.setId (1L) ;
        	user.setUserName ("user_name_1"):
            user.setNote ("note_1" ) ;
            return user;
        }
    }
    

    ​ 然后可以使用AnnotationConfigApplicationContext来构建IOC容器

    package com.springboot.chapter3.config;
    
    import org.apache.log4j.Logger ;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import com.springboot.chapter3.pojo.User;
    public class IoCTest {	
        private static Logger log= Logger . getLogger(IoCTest.class);
        public static 飞roid main (String [] args) {
            ApplicationContext ctx= new AnnotationConfigApplcationContext(AppConfig.class);
            User user= ctx.getBean(User . class);
            log.info(user.getid ());
       }
    }
    

    二、装配Bean

    1.通过扫描装配Bean

    ​ 如果一个个的 Bean 使用注解@Bean 注入 Spring loC 容器中,那将是一件很麻烦的事情。好在Spring 还允许我们进行扫描装配 Bean 到 loC 容器中,对于扫描装配而言使用 的注解是@Component和@ComponentScan。@Component 是标明哪个类被扫描进入 Spring IoC 容器,而@ComponentScan则是标明采用何种策略去扫描装配 Bean

    ​ 我么需要将User.java移动到com.springboot.chapter.config内,对其修改

    package com.springboot.chapter3.config;
    
    @Component("user")
    
    public class User{
    	@Value("1")
    	private Long id;
    	@Value("user_name_1")
    	private String userName;
    	@Value("note_1")
    	private String note
    	
    	/** setter and getter**/
    }
    
    
    • @Component 表明这个类将被 Spring IoC 容器扫描装配 ,其中配置的“ user"则是作为Bean 的名称,当然你也可以不配置这个字符串 ,那么 IoC 容器就会把类名第一个字母作为小写,其他不变作为 Bean 名称放入到 IoC 容器中
    • @Value 将对应的字面量注入到相应的属性当中。

    然后需要改造Appconfig.java

    package com.springboot.chapter3.config;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import com.springboot.chapter3.pojo.User;
    
    
    @Configuration
    @ComponentScan
    public class AppConfig {
    }
    
    • @ComponentScan 用于扫描包, 当没有定义的情况下,只会扫描当前包和其子包

    测试Bean已经被扫描进入了IOC容器

    ApplicationContext ctx
    =new AnnotationConfigApplicationContext{AppConfig.class) ;
    User user= ctx.getBean(User.class);
    log.info(user.getid());
    

    当User 类放到包 com . springboot.chapter3.pojo 中 AppConfig中的注解应该修改为

    @ComponentScan ("com . springboot.chapter3 . * ")
    或
    @ComponentScan(basePackages={"com.springboot.chapter3.pojo"})
    或
    ComponentScan(basePackageClasses = {User . class})
    

    2.自定义第三方Bean

    @Bean(name = "dataSource") 
    public DataSource getDataSource () {
    	Properties props= new Properties();
    
    	rops.setProperty("driver","com.mysql.jdbc.Driver" );
    	props.setProperty("url","jdbc:mysql://localhost:3306/chapter3");
    	props.setProperty ("username","root");
    	props.setProperty ("password","123456");
    	DataSource dataSource = null 
    	try {
    		dataSource = BasicDataSourceFactory.createDataSource (props);
    	} catch (Exception e) {
    		e.printStackTrace();
    	}
    	return dataSource;
    }
    
    

    @Bean 定义了其配置项 name 为“ dataSource 飞 那么 Spring 就会把它返回的对象用名称“ dataSource ” 保存在 loC 容器中

    三、依赖注入

    1.@AutoWired

    • @ Autowired 它注入的机制最基本的一条是根据类型( by type) ,通过BeanFactory,就可以知道 IoC 容器是通过 getBean 方法获取对应 Bean 的,而 getBean 又支持根据类型( by type)或者根据名称( by name )

    • 首先它会根据类型找到对应的 Bean,如果对应类型的 Bean 不是唯一 的,那么它会根据其属性名称和 Bean 的名称进行匹配。如果匹配得上,就会使用该 Bean:如果还无法匹配,就会抛出异常。

    2. @ Primary 和@Quelifier

    @Component
    @Primary
    public class Cat implements Animal {
    }
    

    @Primary 的含义告诉 S pring IoC 容器 , 当发现有多个同样类型的 Bean 时请优先使用我进行注入

    @Autowired
    @Qualifier ( " dog")
    private Animal animal = null; 
    

    @Quelifier 它的配置项 value 需要一个字符串去定义,它将与@Autowired 组合在一起,通过类型和名称一起找到 Bean

    四、生命周期

    ​ Spring IoC 初始化和销毁 Bean 的过程,这便是 Bean 的生命周期的过程 , 它大致分为 Bean 定义、Bean 的初始化、 Bean 的生存期和 Bean 的销 毁 4 个部分

    Bean定义的过程:

    • Spring 通过我们的配置,如@ComponentScan 定义的扫描路径去找到带有@Component 的类 ,这个过程就是一个资源定位的过程 。
    • 一旦找到了资源,那么它就开始解析,并且将定义的信息保存起来 。注意 ,此时还没有初始化 Bean,也就没有 Bean 的实例,它有的仅仅是 Bean 的定义。
    • 然后就会把 Bean 定义发布到 Spring IoC 容器中 。 此时, IoC 容器也只有 Bean 的定义,还是没有 Bean 的实例生成。

    Bean初始化过程:

    ​ 默认让那些 Bean 只是将定义发布到 IoC 容器而不做实例化和依赖注入, 当我们取出来的时候才做初始化和依赖注入等操作 。@ComponentScan 中还有一个配置项 lazyInit,只可以配置 Boolean 值,且默认值为 false ,也就是默认不进行延迟初始化,因此在默认的情况下 Spring 会对 Bean 进行实例化和依赖注入对应的属性值。

    @ComponentScan(basePackages = "com.springboot.chapter3.*", lazyinit = true)
    

    Bean生存期:

    五、条件装配

    package com . springboot chapter3 .condition;
    
    public class DatabaseConditional implements Condition {
    
    
        @Override
        public boolean matches(ConditionContext context,AnnotatedTypeMetadata metadata) {
            //取出环境配置
            Environment env=context.getEnvironment();
            //判断属性文件是否存在对应的数据库配置
            return env.containsProperty("database.driverName")
                && env.containsProperty("database.url")
                && env.containsProperty("database.username")
                && env.containsProperty("database.password
         }
     }    
        
    
    @Bean (name = ” dataSource ” , destroyMethod = ” close ” )
    @ Conditional(DatabaseConditional.class)
    public DataSource getDataSource (
            @Value("${database .driverName}") String driver,
            @Value("${database . url}" ) String url ,
            @Value("${database .username}") String username ,
            @Value("${database . password}") String password
            ){
        Properties props= new Properties ();
        props.setProperty ("driver", driver );
        props.setProperty( "url", url);
        props.setProperty ("username", username);
        props.setProperty ("password", password);
        DataSource dataSource = null ;
        try {
        dataSource = BasicDataSourceFactory.createDataSource(props);
        ) catch (Exception e) {
        	e.printStackTrace();
        }
        return dataSource ;
    }
    

    @Conditional 帮助我们完成条件装配。而它需要配合另 外一个接口
    Condition ( org.springframework .context.annotation.Condition )来完成对应的功能 ,对于 Condition 接口 则要求实现 matches 方法 ,当它返回True时才进行装配

    六、Bean 的作用域

    作用域类型 使用范围 描述
    singleton 所有 S pring 应用 默认值 , loC 容器只存在单例
    prototype 所有 S pring 应用 每当从 IoC 容器中取出一个 Bean ,则创建一个新的 Bean
    session Spring Web 应用 HTTP 会话
    application Spring Web 应用 Web 工程生命周期
    request Spring Web 应用 Web 工程单次请求 ( request)
    globalSession Spring Web 应用 在一个全局的 HTTP Session 中, 一个 Bean 定义对应一个实例 。 实践中基本不使用

    七、引入XML配置Bean

    ​尽管 Spring Boot 建议使用注解和扫描配置 Bean,我们也可以在 Spring Boot 中使用 XML 对 Bean 进行配置 。 这里需要使用的是注解@ImportResource ,通过它可以引入对应的 XML 文件,用 以加载 Bean 。

  • 相关阅读:
    微软面试问题 情商测试
    SQL游标使用实例
    如何减小与“大牛”的差距
    Dotnet面试题
    排序算法对冒泡排序的优化改进算法
    一个SQL实现薪水大于所在部门平均薪水的员工
    ASP.NET中TextBox设置为Readonly后无法取值的解决办法
    jQuery.Autocomplete实现自动完成功能(详解)
    php发送get、post请求的几种方法
    ISO Latin1字符集
  • 原文地址:https://www.cnblogs.com/yanquhonggui/p/11072919.html
Copyright © 2011-2022 走看看