文章目录
- 一、背景与IoC
- 二、注解@Bean
- 1、@Bean注解用法
- 2、@Bean注解源码
- 3、@Bean注解演示
一、背景与IoC
之前的代码书写现状—耦合度偏高。如下图,业务层需要数据层实现类对象BookDaoImpl,于是自己new了一个,此时,当数据层类名改为BookDaoImpl2
,业务层代码也得跟着修改。
基于上面的问题,我们考虑使用对象时,在程序中不要主动使用new产生对象,转换为由外部提供对象
这就是Ioc,Inversion of Control,即控制反转,这种思想的核心在于把对象的创建控制权由程序转移到外部 ,以达到解耦的目的。
- Spring技术对Ioc思想进行了实现落地==>提供一个
Ioc容器
,来充当Ioc思想中的"外部" - Ioc容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在Ioc容器中统称
Bean
- 在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入(DI,Dependency Injection)
小结:
核心:
Ioc容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在Ioc容器中统称`Bean
二、注解@Bean
1、@Bean注解用法
Spring的@Bean注解用于告诉方法,产生一个Bean对象,然后这个Bean对象交给Spring管理。产生这个Bean对象的方法Spring只会调用一次,随后这个Spring将会将这个Bean对象放在自己的IOC容器中。
@Bean放在方法上,告诉被注解的方法,你去产生一个Bean,然后交给Spring容器管理。
//简单例子
class Test{
@Bean
public AccountObj accountObj(){
return new AccountObj();
}
}
以数据源Bean的创建为例:
2、@Bean注解源码
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
@AliasFor("name")
String[] value() default {};
@AliasFor("value")
String[] name() default {};
Autowire autowire() default Autowire.NO;
String initMethod() default "";
String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
}
# AliasFor可以定义一个注解中的两个属性互为别名
# 复习:
# Retention这个元注解用来标注“被标注的注解”最终保存在哪里
@Retention(RetentionPolicy.SOURCE) 表示该注解只能保留在Java源文件中
@Retention(RetentionPolicy.CLASS) 表示该注解只能保留在class文件中
@Retention(RetentionPolicy.RUNTIME) 表示该注解只能保留在class文件中,且可以被反射机制所读取
- @Bean注解可以用在方法上,也可用在注解类型上
- @Retention(RetentionPolicy.RUNTIME) 即该注解可以被反射机制所读取
- value:name属性的别名,String数组类型,即可多个。不使用注解的其他属性时,value就是默认属性
- name:bean的名称,同样是String数组,如果不写则默认Bean的名称为所注解的方法的名称
- value和name如果都要使用,则值要一致
- autowire:自动装配,取值是Autowire类型的枚举,默认不开启
/ 枚举确定自动装配状态:即,bean是否应该使用setter注入由Spring容器自动注入其依赖项。
// 这是Spring DI的核心概念
public enum Autowire {
// 常量,表示根本没有自动装配。
NO(AutowireCapableBeanFactory.AUTOWIRE_NO),
// 常量,通过名称进行自动装配
BY_NAME(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME),
// 常量,通过类型进行自动装配
BY_TYPE(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE);
private final int value;
Autowire(int value) {
this.value = value;
}
public int value() {
return this.value;
}
public boolean isAutowire() {
return (this == BY_NAME || this == BY_TYPE);
}
}
- initMethod:即初始化方法,在bean实例化时调用
# 下面这种方式也能实现初始化,但Spring不推荐
//InitializationBean接口允许bean在合适的时机通过设置注解的初始化属性从而调用初始化方法
//InitializationBean 接口有一个定义好的初始化方法
void afterPropertiesSet() throws Exception;
# 不推荐使用InitializationBean接口
public class InitBean implements InitializingBean {
public void afterPropertiesSet() {}
}
# Spring推荐使用@PostConstruct注解或者指定初始化方法来完成初始化
- destroyMethod: 调用bean示例在关闭上下文的时候执行,例如JDBC的close()方法,或者SqlSession的close()方法
//DisposableBean 接口的实现允许在bean销毁的时候进行回调调用,DisposableBean 接口之后一个单个的方法
# Spring不推荐
void destroy() throws Exception;
# Spring 推荐使用@PreDestory注解或者为@Bean注解提供 destroyMethod 属性。
3、@Bean注解演示
定义类:
public class MyBean {
public MyBean(){
System.out.println("MyBean Initializing");
}
public void init(){
System.out.println("Bean 初始化方法被调用");
}
public void destroy(){
System.out.println("Bean 销毁方法被调用");
}
}
定义配置类:
@Configuration
public class AppConfig {
@Bean(initMethod = "init", destroyMethod = "destroy")
public MyBean myBean(){
return new MyBean();
}
}
写测试类,查看初始化和销毁方法的调用时机:
public class SpringBeanApplicationTests {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
context.getBean("myBean");
((AnnotationConfigApplicationContext) context).destroy();
//((AnnotationConfigApplicationContext) context).close();
}
}
效果: