IOC容器是一个管理Bean的容器,它要求所有的Bean都需要实现接口
BeanFactory是一个顶级的容器接口
BeanFactory.class 源码
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
//获取Bean
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;
//获取Bean的提供者
<T> ObjectProvider<T> getBeanProvider(Class<T> var1);
<T> ObjectProvider<T> getBeanProvider(ResolvableType var1);
//是否包含该Bean
boolean containsBean(String var1);
//是否是单例
boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
//是否是原型
boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;
//是否类型匹配
boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;
//获取类型
@Nullable
Class<?> getType(String var1) throws NoSuchBeanDefinitionException;
//获取别名
String[] getAliases(String var1);
}
从上面可以结合中文注释可以看出 BeanFactory中提供的方法的一些作用
- isSingleton 判断这个Bean是否是单例的,默认情况下容器中的Bean都是单例的
- isPrototype 和isSingleton的相反,如果返回true每次从容器当中获取一个Bean都是重新创建
- BeanFactory提供的方法是一些常用的对Bean获取方法,但是工作中可能我们的需求更大所以需要更多。在此之上也提供了一个更高级的注解ApplicationContext 在使用IOC容器的时候,大部分类都实现来自己 ApplicationCOntext接口。
演示框架采用SpringBoot最新版本
@Data
public class Users {
private Integer id;
private String userName;
private String userId;
public Users(Builder builder) {
id = builder.id;
userId = builder.userId;
userName = builder.userName;
}
//Builder构造器模式
public static class Builder {
int id;
String userName;
String userId;
public Builder(int id, String userName, String userId) {
this.id = id;
this.userName = userName;
this.userId = userId;
}
public Builder id(int id) {
this.id = id;
return this;
}
public Builder userName(String userName) {
this.userName = userName;
return this;
}
public Builder userId(String userId) {
this.userId = userId;
return this;
}
public Users builder() {
return new Users( this );
}
}
}
上面采用构造器模式 原因只是 个人想复习一下 没有其他想表达的意思,望别误入
//表示一个配置文件
@SuppressWarnings("ALL")
@Configuration
public class ApplicationConfig {
//表示声明一个user的Bean如果没有user那么会直接采用方法名作为这个Bean的名称
@Bean("user")
public Users initUser() {
Users users = new Users.Builder( 1, "zhangsan", "lucy" ).builder();
// Users users=new Users( );
// users.setId( 1 );
// users.setUserName( "张三" );
// users.setUserId( "Lucy" );
return users;
}
}
测试
public class IocTest {
//SpringBoot自带日志
private static Logger logger= LoggerFactory.getLogger( IOContext.class );
public static void main(String[] args) {
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(
ApplicationConfig.class );
Users bean = applicationContext.getBean( Users.class );
logger.debug( bean.toString() );
}
}
14:57:17.223 [main] DEBUG com.fasterxml.jackson.core.io.IOContext - Users(id=1, userName=zhangsan, userId=lucy)
我们可以通过第一种方式加载Bean
还可以通过扫描的方式加载Bean
采用SpringBoot的ComponentScan 扫描 不多BB直接看源码 用法 自行百度
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
//定义扫描的包
@AliasFor("basePackages")
String[] value() default {};
//扫描包路径 默认扫描当前包以及他的子包
@AliasFor("value")
String[] basePackages() default {};
//定义扫描的类
Class<?>[] basePackageClasses() default {};
//BeanName生成器
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
//作用域解析器
Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
//作用域代理器
ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
//资源匹配模式
String resourcePattern() default "**/*.class";
//是否启用默认过滤 默认true
boolean useDefaultFilters() default true;
//满足条件扫描 不满足的时候不扫描
ComponentScan.Filter[] includeFilters() default {};
当不满足条件时间扫描 满足的时候 过滤
ComponentScan.Filter[] excludeFilters() default {};
//是否延迟加载 默认为false
boolean lazyInit() default false;
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Filter {
FilterType type() default FilterType.ANNOTATION;
@AliasFor("classes")
Class<?>[] value() default {};
@AliasFor("value")
Class<?>[] classes() default {};
String[] pattern() default {};
}
}
IoC 的三个经典问题
对于 IoC 有三个经典问题:谁控制谁?控制了什么?怎么实现了反转?很多博客里都进行了一个回答,笔者也按照自己的故事模式进行一个回答。
* “谁控制谁?”:IoC / DI 容器控制应用程序
* 控制了什么?:IoC / DI 容器控制对象本身的创建、实例化,以及控制对象之间的依赖关系;
* 开发之中的对象已经全部交由 IoC 容器来管理了,那我们在获取对象的时候,就得由 IoC 容器来给我们提供;
2.3 DI 的三个经典问题
* “谁依赖谁?”:应用程序依赖于 IoC 容器;
* “谁注入了谁?”:IoC 容器把对象注入于应用程序;
* “注入了什么?”:注入应用程序需要的外部资源,比如有依赖关系的对象