全注解下的IOC
Posted yanquhonggui
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了全注解下的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 AnnotationConfigApplicationContextAppConfig.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 容器中
三、依赖注入
[email protected]
@ 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 。
以上是关于全注解下的IOC的主要内容,如果未能解决你的问题,请参考以下文章