java web 46 : SpringBoot

 

 

 

SpringBoot 项目在启动时,首先基于启动入口类上的注解描述,进行自动配置并扫描指定包以及子包中的类进行加载,

然后检测类上是否有Spring框架中指定的注解描述(例如@Component,@Controller,@Service等)。

假如有,则将类交给Spring框架中的BeanFactory工厂接口的实现类对象,此工厂对象会基于反射创建Bean的实例,

假如此Bean指定了生命周期方法,还会调用生命周期方法。

当实例创建以后,Spring框架还会基于类的作用域描述,将实例存储到不同作用域的容器中。以实现Bean对象的科学应用。

 

图中描述了DefaultCacheTests类与DefaultCache类的关系,这两个类通过指定注解(@SpringBootTest,@Component)进行了描述,

其意图是告诉spring框架这个两个类的实例的创建由Spring负责,并且由Spring框架基于@Autowired注解的描述完成DefaultCacheTests实例中有关DefaultCache类型的值的注入(DI)。

 

NoSuchBeanDefinitionException的原因

类在项目启动时都会加载,但是否
1.类所在的包是否在启动类所在包或子包
2.类是否使用了spring特定注解

NoUniqueBeanDefinitionException:

实现类对象有多个,spring框架无法选择

package com.company.common.pool;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

/**
 * @Component
 *         将此类交给spring管理,spring在何时创建此对象
 * @Lazy    ---延迟加载
 *         此注解的含义为,告诉spring框架,如果暂时用不到,就暂时不要创建此类实例
 *         适用于不常使用的大对象,一个对象创建之后长时间不用会消耗资源
 *         默认为@Lazy(true)
 *         只针对singleton作用域的对象
 * @Scope("singleton")    ---作用域
 *         默认是单例作用域"singleton",这个类在实例在一个spring容器中只有一份,但同类型不同名会在容器中存多份,单例是指同类同名
 *         适用于频繁使用
 *         单例必须考虑线程安全问题
 *         "prototype",每次从spring容器获取对象都会创建新的实例,但spring容器不负责销毁
 *         适用于应用次数少,prototype域的对象不会存入容器池
 * @PostConstruct    ---对象构建以后执行,用于执行初始化操作
 * @PreDestroy        ---在单例对象销毁前执行
 *         spring容器在销毁之前,会先将容器(Bean池)中的对象进行移除,
 *         如果对象中定义了生命周期销毁方法,此时会先调用生命周期销毁方法(进行一些资源释放操作),再进行移除
 *         prototype域的对象不会存入池,不会调用@PreDestroy方法
 */
@Scope("singleton")
@Lazy
@Component
public class ObjectPool {
    public ObjectPool() {
        System.out.println("ObjectPool()");
    }
    
    @PostConstruct
    public void init() {
        //    生命周期初始化
        System.out.println("init()");
    }
    @PreDestroy
    public void close() {
        //    生命周期销毁前执行
        System.out.println("close()");
    }
}

 

package com.company.common.pool;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class ObjectPoolTests {
    @Autowired
    private ObjectPool objectPool01;
    @Autowired
    private ObjectPool objectPool02;
    @Test
    void testObjectPool() {
        System.out.println(objectPool01);
        System.out.println(objectPool02);
        System.out.println(objectPool01==objectPool02);
    }
}

 

package com.company.pj.common.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import com.company.pj.common.cache.Cache;
/**
* @Autowired    由spring框架定义,用于描述类中属性或相关方法(例如构造方法)。
 *     Spring框架在项目运行时假如发现由他管理的Bean对象中有使用@Autowired注解描述的属性或方法,
 *     可以按照指定规则为属性赋值(DI)。其基本规则是:
 *     首先要检测容器中是否有与属性或方法参数类型相匹配的对象,假如有并且只有一个则直接注入。
 *     其次,假如检测到有多个,还会按照@Autowired描述的属性或方法参数名查找是否有名字匹配的对象,有则直接注入,没有则抛出异常。
 *     最后,假如我们有明确要求,必须要注入类型为指定类型,
*     名字为指定名字的对象还可以使用@Qualifier注解对其属性或参数进行描述(此注解必须配合@Autowired注解使用)。
 *
* @Qualifier    实现类有多个时,注入属性名字与实现类名不同或实现类名有多个时(无法一对一匹配)
 *     可以用此注解指定实现类
 */
/** * @Component 描述类时,用于告诉spring框架,由spring通过反射构建此类型对象 * 执行@Autowired构造方法,此时需要取到Cache对象 * @Autowired 三种写法 */ @Component("searchService") public class SearchService { @Autowired //1. 修饰变量 @Qualifier("weakCache") private Cache cache; @Autowired //2. 修饰有参构造 public SearchService(@Qualifier("softCache") Cache cache) { System.out.println("SearchService有参"); this.cache = cache; } public SearchService() { System.out.println("SearchService无参"); } @Autowired //3. 修饰setter,配合无参构造使用 @Qualifier("softCache") public void setCache(Cache cache) { System.out.println("setter"); this.cache = cache; } public Cache getCache() { return cache; } }

 

 

posted @ 2020-08-25 16:16  Saturn5  阅读(45)  评论(0)    收藏  举报