目录
关于Bean Name 被Spring管理的对象都可以称之为:Spring Bean。
关于Spring自动调用构造方法 使用组件扫描来创建Spring Bean时,Spring框架会自动调用组件类的构造方法,规则如下:
IoC(Inversion of Control): 控制反转,即将各对象的控制权交给了Spring框架
Spring框架主要解决了创建对象、管理对象的相关问题。
由于Spring会保管(管理)所创建的对象,当需要时,可以通过Spring获取这些对象,所以,Spring框架也被称之为“Spring容器”。
Spring框架的基础依赖项是spring-context。
通过Spring创建对象 -- 1. 组件扫描
在配置类上通过@ComponentScan注解,可以配置“组件扫描”,则加载此配置类时,Spring框架就会开启组件扫描,过程中,会扫描对应的包及其子孙包,如果这些包中存在“组件类”,则Spring会自动创建这些组件类的对象。
在Spring Boot项目中,启动类上添加了@SpringBootApplication注解,此注解的元注解中就包含@SpringBootConfiguration和@ComponentScan,并且,@SpringBootConfiguration的元注解中包含@Configuration,即:
@SpringBootApplication
-- @SpringBootConfiguration
-- -- @Configuration
-- @ComponentScan
所以,在默认情况下,Spring Boot启用时就会执行组件扫描!
在@ComponentScan注解上可以配置扫描的根包(basePackage),如果没有配置此属性,则默认为当前配置类所在的包!
在Spring Boot项目中,可以配置@SpringBootApplication的scanBasePackages属性来指定组件扫描的根包。
仅当添加了组件注解的类才被视为“组件类”,典型的组件注解是@Component,另外,还有其它组件注解:
@Controller:添加在控制器类上的注解
@Service:添加在业务类上的注解
@Repository:添加在数据访问类上的注解 在Spring框架的作用范围内,以上3个注解与@Component注解的作用、用法是完全等效的,只是语义不同!
在Spring框架中,另外还有@Configuration注解也是组件注解的一种,但是,Spring框架会使用“CGLib代理模式”来处理!
在Spring MVC框架中,又加入了一些新的组件注解,包括:
@RestController
@ControllerAdvice
@RestControllerAdvice
通过Spring创建对象 -- 2. @Bean方法 在配置类中,可以自定义方法,方法的返回值类型就是你希望Spring创建对象的类型,并且,在方法体中,自行编写可以创建出此类型对象的代码,最终,在方法上添加@Bean注解,例如:
@Configuration
public class BeanConfiguration {
@Bean
public ICategoryService categoryService() {
return new CategoryServiceImpl();
}
@Bean
public CategoryController categoryController(ICategoryService categoryService) {
// 假设CategoryController中存在带参数的构造方法
return new CategoryController(categoryService);
}
@Bean
public AlbumController albumController() {
return new AlbumController();
}
}
当加载此配置类时,Spring框架会自动调用这些@Bean方法,则Spring框架会得到这些方法返回的对象!
关于通过Spring创建对象的做法的选取 如果需要创建对象的类是自定义的,可以优先考虑使用组件扫描的做法!
如果需要创建对象的类不是自定义的,则只能使用@Bean方法的做法!
关于Bean Name 被Spring管理的对象都可以称之为:Spring Bean。
每个Spring Bean都有Name,即名称。
如果是通过组件扫描创建的Spring Bean,默认的名称取决于类型的名称,如果类名的第1个字母是大写的,且第2个字母是小写的,则名称是将类名的首字母改为小写,例如CategoryServiceImpl的Bean名称就是categoryServiceImpl,如果不符合首字母大写且第2个字母小写,则Bean名称就是类名。另外,还可以在配置组件注解的属性来指定某个名称,例如:
@Service("categoryService")
public class CategoryServiceImpl implements ICategoryService {
}
如果是通过@Bean方法创建的Spring Bean,默认名称就是@Bean方法的名称,或者,可以配置@Bean注解的参数来指定某个名称,例如:
@Configuration
public class BeanConfiguration {
@Bean("categoryService")
public ICategoryService categoryService() {
return new CategoryServiceImpl();
}
}
关于自动装配 自动装配:当组件类的属性需要值时,或被Spring调用的方法的参数需要值时,Spring框架会自动从容器找到合适的对象,用于为此属性 / 此参数赋值!
合适的对象:名称匹配的,类型匹配的
例如,在属性上添加@Autowired注解,即可表示“需要自动装配”的意义,则Spring框架会尝试为此属性执行自动装配:
@RestController
public class CategoryController {
@Autowired
private ICategoryService categoryService;
}或
@Service
public class CategoryServiceImpl implements ICategoryService {
@Autowired
private CategoryMapper categoryMapper;
}
在处理自动装配时,可用的注解有@Resource和@Autowired,它们的区分主要在于:
@Resource是javax.annotation包中的注解, @Autowired是Spring注解
如果你不使用Spring框架,而是使用其它框架实现自动装配,@Resource注解均可使用,而仅当使用Spring时才可以使用
@Autowired
由于Spring框架普及程度非常高,所以使用@Autowired是完全没有问题的
@Resource是优先根据名称来匹配的,如果无匹配,则按照类型来匹配,而@Autowired是优先按照类型查找匹配的对象,如果存在多个类别匹配的,则按照名称来匹配 关于名称的匹配,需要Spring Bean名称与被装配的属性 / 参数的名称保持完全一致。
当使用@Resource时,可以配置此注解的name属性,用于指定Spring Bean的名称,例如:
@Resource(name = "categoryServiceImpl")
private ICategoryService categoryService;
当使用@Autowired时,只能匹配使用@Qualifier注解来指定Spring Bean的名称,例如:
@Autowired @Qualifier("categoryServiceImpl") private ICategoryService categoryService;
如果某个方法的参数需要注入值,与参数匹配的Spring Bean超过1个,且各Spring Bean与参数名称都不匹配,使用@Resource是无解的,只能通过在各参数上添加@Qualifier来配置Spring Bean的名称!
关于@Autowired的装配过程
首先,会查找匹配类型的Spring Bean的数量,然后:
0个:取决于@Autowired的required属性的值
true:无法装配,在启动时报错,例如:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'cn.tedu.csmall.product.service.ICategoryService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
false:放弃装配,在启用时不会报错,后续使用过程中可能会出现NPE
1个:直接装配,且成功
多个:尝试按照名称进行匹配,如果可以匹配,则成功装配,否则,启动时报错,例如:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'cn.tedu.csmall.product.service.ICategoryService' available: expected single matching bean but found 2: categoryServiceImpl,categoryServiceImpl2
关于为属性注入值的做法 当组件类的属性需要值时,有3种可行的做法:
字段注入:
在属性上添加@Autowired,例如:
@Service
public class CategoryServiceImpl implements ICategoryService {
@Autowired
private CategoryMapper categoryMapper;
}
Setter注入:
在方法上添加@Autowired,并在方法体中为属性赋值,例如:
@Service
public class CategoryServiceImpl implements ICategoryService {
private CategoryMapper categoryMapper;
@Autowired
public void setCategoryMapper(CategoryMapper categoryMapper) {
this.categoryMapper = categoryMapper;
}
}
构造方法注入:
在被Spring调用的构造方法上添加参数,并通过此参数为属性赋值,例如:
@Service
public class CategoryServiceImpl implements ICategoryService {
private CategoryMapper categoryMapper;
public CategoryServiceImpl(CategoryMapper categoryMapper) {
this.categoryMapper = categoryMapper;
}
}
注意:理论上并不推荐字段注入,所以,在IntelliJ IDEA中也有相关提示:
理论上推荐的是构造方法注入,但是,构造方法注入对可能出现的增减属性并不友好,并且,当需要注入值的属性较多时,构造方法的参数列表也会很长,这是不合适的!
注意:在属性上使用@Resource注解也可以实现自动装配,并且,IntelliJ IDEA并不会提示灰色的波浪线,但是,并不表示“推荐使用@Resource取代@Autowired”,只是IntelliJ IDEA并不检查@Resource注解,并且,@Resource注解不支持其它注入方式。
关于Spring自动调用构造方法 使用组件扫描来创建Spring Bean时,Spring框架会自动调用组件类的构造方法,规则如下:
如果类没有显式的添加构造方法,则会自动调用默认的构造方式 如果类中仅有1个构造方法,无论是否有参数,Spring都会尝试自动调用
如果类中有多个构造方法,在默认情况下,Spring将自动调用无参数的构造方法(如果存在的话),如果你希望Spring调用特定的构造方法,则需要在此构造方法上添加@Autowired 关于Spring Bean的作用域 所有Spring Bean默认都是单例的,如果希望某个Spring Bean不是单例的,可以通过@Scope注解进行配置。
如果是通过组件扫描创建的Spring Bean,则在组件类上添加
@Scope("prototype")
如果是通过@Bean方法创建的Spring Bean,则在@Bean方法上添加@Scope("prototype")
注意:Spring Bean的表现特征可能是单例的,但Spring并不是通过单例模式来实现的
所有单例的Spring Bean默认都是预加载(相当于单例的饿汉式)的,如果希望某个Spring Bean是懒加载的,可以通过@Lazy注解进行配置。
如果是通过组件扫描创建的Spring Bean,则在组件类上添加@Lazy 如果是通过@Bean方法创建的Spring Bean,则在@Bean方法上添加 @Lazy
关于Spring Bean的生命周期
在Spring Bean归属的类中,可以自定义“初始化”和“销毁”的生命方法,则Spring框架会在创建对象之后自动调用“初始化”的生命周期方法,并在销毁对象之前调用“销毁”的生命周期方法。
关于自定义的方法:
应该是公有的 应该是void返回值类型 销毁方法可以使用布尔类型的返回值 方法名称是自定义的 参数列表应该为空 仅当添加了@PostConstruct注解的方法,才是“初始化”的生命周期方法,此方法会在构造方法之后自动执行。
仅当添加了@PreDestroy注解的方法,才是“销毁”的生命周期方法,此方法会在销毁当前类的对象之前自动执行。
例如:
@PostConstruct
public void init() {
log.debug("执行生命周期方法:CategoryController的初始化方法");
}
@PreDestroy
public void destroy() {
log.debug("执行生命周期方法:CategoryController的销毁方法");
}
关于IoC与DI
IoC(Inversion of Control): 控制反转,即将各对象的控制权交给了Spring框架
DI(Dependency Injection):依赖注入,即为各依赖项注入值
Spring框架负责的创建对象、管理对象都是Spring IoC的表现。
Spring框架通过DI完成了IoC,即DI是实现手段,IoC是需要实现的目标。
关于Spring AOP 再议~~~~~~