我们专注攀枝花网站设计 攀枝花网站制作 攀枝花网站建设
成都网站建设公司服务热线:400-028-6601

网站建设知识

十年网站开发经验 + 多家企业客户 + 靠谱的建站团队

量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决

Spring容器怎么配置

这篇文章主要讲解了“Spring容器怎么配置”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Spring容器怎么配置”吧!

创新互联建站服务项目包括新宾网站建设、新宾网站制作、新宾网页制作以及新宾网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,新宾网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到新宾省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!

1.容器概览

Spring 中的 Ioc 容器,我们可以大致上分为两种:

  • BeanFactory
  • ApplicationContext
 

1.1 BeanFactory

BeanFactory 是最最基础的 IoC 容器,它提供了一个 IoC 容器所需的基本功能。在本系列前面文章中我们所用到的 XmlBeanFactory 就是它的实现之一。

BeanFactory 默认采用延迟初始化策略,即当容器启动时,并未完成 Bean 的初始化,只有当调用到该 Bean 的实例时,才会完成其初始化操作,并进行依赖注入。

例如如下代码:

XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
User user = factory.getBean(User.class);
 

当第一行代码执行的时候,beans.xml 中配置的 User 对象并未进行初始化,只有当第二行 getBean 方法调用时,User 对象才进行了初始化操作。

这样设计的好处是容器启动速度快,因为要做的事情比较少。

 

1.2 ApplicationContext

ApplicationContext 是在 BeanFactory 的基础上实现的,BeanFactory 的功能它都有,算是一种高级容器。

ApplicationContext 在 BeanFactory 的基础上提供了事件发布、国际化等功能。

同时,ApplicationContext 和 BeanFactory 还有一个很大的不同在于 ApplicationContext 在容器启动时,就会完成所有 Bean 的初始化,这也就以为着容器启动时间较长,并且对系统资源要求也较高。

例如如下一段代码:

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
 

当这段代码执行时,beans.xml 中配置的 User 对象就会完成初始化操作。

 

2.BeanFactory

BeanFactory 的继承关系图太大了,放在文章里显示不全。小伙伴们可以在 IDEA 中自行查看,我这里就不贴图出来了。

我们来看下 BeanFactory 的源码:

public interface BeanFactory {
 String FACTORY_BEAN_PREFIX = "&";
 Object getBean(String name) throws BeansException;
  T getBean(String name, Class requiredType) throws BeansException;
 Object getBean(String name, Object... args) throws BeansException;
  T getBean(Class requiredType) throws BeansException;
  T getBean(Class requiredType, Object... args) throws BeansException;
  ObjectProvider getBeanProvider(Class requiredType);
  ObjectProvider getBeanProvider(ResolvableType requiredType);
 boolean containsBean(String name);
 boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
 boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
 boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
 boolean isTypeMatch(String name, Class typeToMatch) throws NoSuchBeanDefinitionException;
 @Nullable
 Class getType(String name) throws NoSuchBeanDefinitionException;
 @Nullable
 Class getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;
 String[] getAliases(String name);
}
 

可以看到,BeanFactory 主要提供了一些和 Bean 相关的查询方法。

FACTORY_BEAN_PREFIX

这是定义的 FactoryBean 前缀,具体参考Spring 源码第 9 篇,深入分析 FactoryBean。

getBean

getBean 方法一共有五个。

在获取一个 Bean 的时候,可以指定 Bean 的名字,也可以指定 Bean 的类型,也可以同时指定,这个好理解。

还有两个重载的方法里边有一个 args 参数,这个可能有的小伙伴们没怎么用过,我这里稍微解释下。

其实我们大概能猜出来 args 是获取 Bean 时所需要的参数,如果使用该方法给 Bean 配置参数,需要将 Bean 的 scope 设置为 prototype,这就意味着每次获取 Bean 的时候,才去进行 Bean 的初始化(否则配置的参数无法生效)。

松哥通过一个例子来给大家演示下。

首先我们提供一个 User 类:

public class User {
    private String username;
    private Integer age;

    public User(String username, Integer age) {
        this.username = username;
        this.age = age;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", age=" + age +
                '}';
    }
}
 

可以看到,User 类只有一个有参的构造方法。

接下来我们在 XML 文件中进行配置,XML 文件中需要配置 User 类的构造方法参数,我们可以配置为 null,同时记得设置 scope 属性为 prototype。


    
    

 

最后再通过如下方式加载 Bean:

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
User user = ctx.getBean(User.class,new Object[]{"javaboy",99});
System.out.println("user = " + user);
 

最终打印结果如下:

user = User{username='javaboy', age=99}
 

可以看到,为 Bean 配置的参数都生效了。

getBeanProvider

方法用于获取指定 Bean 的提供者,可以看到它返回的是一个 ObjectProvider,该类扩展自 ObjectFactory,从 Spring4.3 时开始提供。

可能大家对 ObjectProvider 接触较少,这里我也稍微说一下。

先来看 ObjectFactory:

@FunctionalInterface
public interface ObjectFactory {
 T getObject() throws BeansException;
}
 

ObjectFactory 有点类似于我们在 Spring 源码第 9 篇,深入分析 FactoryBean 一文中所讲的 FactoryBean。

不同的是,ObjectFactory 中只有一个 getObject 方法,该方法可以返回 Object 实例。ObjectFactory 与 FactoryBean 相似,但是后者的实现通常是在 BeanFactory 中定义为 SPI 实例,而此类的实现通常是作为 API 注入给其他 Bean。

再来看 ObjectProvider(部分):

public interface ObjectProvider extends ObjectFactory, Iterable {
    //返回指定类型的 bean, 如果容器中不存在, 抛出 NoSuchBeanDefinitionException 异常;如果容器中有多个此类型的 bean, 抛出 NoUniqueBeanDefinitionException 异常
 T getObject(Object... args) throws BeansException;
    //如果指定类型的 bean 注册到容器中, 返回 bean 实例, 否则返回 null
 @Nullable
 T getIfAvailable() throws BeansException;
    //如果指定类型的 bean 在容器中只有一个 bean, 返回 bean 实例, 如果不存在则返回 null;如果容器中有多个此类型的 bean, 抛出 NoUniqueBeanDefinitionException 异常
 @Nullable
 T getIfUnique() throws BeansException;
    // Spring5.0 之后提供,返回指定类型 Bean 的迭代器
 @Override
 default Iterator iterator() {
  return stream().iterator();
 }
    //转为 Stream
 default Stream stream() {
  throw new UnsupportedOperationException("Multi element access not supported");
 }
 default Stream orderedStream() {
  throw new UnsupportedOperationException("Ordered element access not supported");
 }
}
 

这是 ObjectProvider 的源码,那么它有什么用呢?松哥举个简单例子。

在 Spring4.3 之前。

假设我有一个 UserDao,如下:

@Repository
public class UserDao {
}
 

还有一个 UserService,如下:

@Service
public class UserService {
    private UserDao userDao;

    @Autowired
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public String toString() {
        return "UserService{" +
                "userDao=" + userDao +
                '}';
    }
}
 

在 UserService 中注入 UserDao 时,必须明确给出 @Autowired 注解。

这看起来不够优雅!

从 Spring4.3 开始,在 UserService 中注入 UserDao 时,如果构造方法只有一个参数,可以不用添加 @Autowired 注解,像下面这样:

@Service
public class UserService {
    private UserDao userDao;

    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public String toString() {
        return "UserService{" +
                "userDao=" + userDao +
                '}';
    }
}
 

但是如果 UserDao 为 null,则会导致 UserService 初始化失败,通过 ObjectProvider 可以解决,如下:

@Service
public class UserService {
    private UserDao userDao;

    public UserService(ObjectProvider userDao) {
        this.userDao = userDao.getIfUnique();
    }

    @Override
    public String toString() {
        return "UserService{" +
                "userDao=" + userDao +
                '}';
    }
}
 

这就是 ObjectProvider。好啦,扯远了,我们回到 BeanFactory 继续看它里边的方法。

containsBean

判断容器中是否包含某个 Bean。

isSingleton

判断某个 Bean 是否是单例的。

isPrototype

判断某个 Bean 是否是 prototype。

isTypeMatch

返回指定名称的 Bean 是否匹配指定的类型。

getType

返回指定名称的 Bean 对应的数据类型。

getAliases

返回 Bean 的别名。

这就是 BeanFactory 中定义的所有方法,可以看到,基本上都是容器相关的查询方法,接下来将在 BeanFactory 的各种实现类中,对其进行实现。

 

3.二级接口

BeanFactory 作为 IoC 容器中最顶层的定义,没有继承任何接口,我们可以称之为一级接口,直接继承自 BeanFactory 的接口有三个,我们称之为二级接口。

 

3.1 HierarchicalBeanFactory

HierarchicalBeanFactory 继承自 BeanFactory,定义了工厂分层,在其基础上又扩展了两个方法:

public interface HierarchicalBeanFactory extends BeanFactory {
 BeanFactory getParentBeanFactory();
 boolean containsLocalBean(String name);
}
 
  • getParentBeanFactory 方法返回 Bean 工厂的父工厂,实现了工厂分层。
  • containsLocalBean 方法则判断本地工厂是否包含这个 Bean。

HierarchicalBeanFactory 有一个接口 ConfigurableBeanFactory,ConfigurableBeanFactory 接口继承自 HierarchicalBeanFactory 和 SingletonBeanRegistry,其中 SingletonBeanRegistry 这个接口定义了对单例 Bean 的定义以及获取方法。也就是说,ConfigurableBeanFactory 中兼具工厂分层和单例处理功能。同时,在 HierarchicalBeanFactory 中 getParentBeanFactory 所 get 到的对象,也是在 ConfigurableBeanFactory 中完成配置。

 

3.2 AutowireCapableBeanFactory

AutowireCapableBeanFactory 继承自 BeanFacotory,它扩展了自动装配的功能。

public interface AutowireCapableBeanFactory extends BeanFactory {
 int AUTOWIRE_NO = 0;
 int AUTOWIRE_BY_NAME = 1;
 int AUTOWIRE_BY_TYPE = 2;
 int AUTOWIRE_CONSTRUCTOR = 3;
 @Deprecated
 int AUTOWIRE_AUTODETECT = 4;
 String ORIGINAL_INSTANCE_SUFFIX = ".ORIGINAL";
  T createBean(Class beanClass) throws BeansException;
 Object createBean(Class beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
 void autowireBean(Object existingBean) throws BeansException;
 Object autowire(Class beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
 void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck) throws BeansException;
 Object configureBean(Object existingBean, String beanName) throws BeansException;
 Object initializeBean(Object existingBean, String beanName) throws BeansException;
 void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException;
 Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException;
 Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException;
 void destroyBean(Object existingBean);
  NamedBeanHolder resolveNamedBean(Class requiredType) throws BeansException;
 Object resolveBeanByName(String name, DependencyDescriptor descriptor) throws BeansException;
 @Nullable
 Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException;
 @Nullable
 Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
   @Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;
}
 

首先通过五个常量定义了五种不同的装配策略,分别是:不自动装配、通过名称自动装配、通过类型自动装配、通过构造方法自动装配,还有一个过期的常量。

ORIGINAL_INSTANCE_SUFFIX 则是初始化实例给定名称时约定的后缀,该后缀会添加到类的全路径后面,例如:com.mypackage.MyClass.ORIGINAL

createBean 方法用来创建 Bean 实例;autowire* 方法则用来完成自动装配;configureBean 用来配置 BeaninitializeBean 用来初始化 BeanapplyBeanPropertyValues 将指定 beanBeanDefinition 应用到一个已经存在的 Bean 上;applyBeanPostProcessorsBeforeInitialization/applyBeanPostProcessorsAfterInitialization 调用 Bean 的后置处理器;destroyBean 方法用来销毁 Beanresolve* 方法用来解析 Bean

 

3.3 ListableBeanFactory

ListableBeanFactory 继承自 BeanFacotory,该接口可以列出工厂可以生产的所有实例。

public interface ListableBeanFactory extends BeanFactory {
 boolean containsBeanDefinition(String beanName);
 int getBeanDefinitionCount();
 String[] getBeanDefinitionNames();
 String[] getBeanNamesForType(ResolvableType type);
 String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit);
 String[] getBeanNamesForType(@Nullable Class type);
 String[] getBeanNamesForType(@Nullable Class type, boolean includeNonSingletons, boolean allowEagerInit);
  Map getBeansOfType(@Nullable Class type) throws BeansException;
  Map getBeansOfType(@Nullable Class type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException;
 String[] getBeanNamesForAnnotation(Class annotationType);
 Map getBeansWithAnnotation(Class annotationType) throws BeansException;
 @Nullable
  A findAnnotationOnBean(String beanName, Class annotationType) throws NoSuchBeanDefinitionException;
}
 
  • containsBeanDefinition:判断容器是否包含某一个 Bean 的定义。
  • getBeanDefinitionCount:获取 BeanDefinition 数量。getBeanDefinitionCount 和 containsBeanDefinition 执行效率较低,慎用。
  • getBeanDefinitionNames:获取所有 Bean 的名字。
  • getBeanNamesForType:返回指定类型的 BeanName。
  • getBeansOfType:返回指定类的名称和 Bean Map(相同类型的 Bean 可能存在多种实例)。
  • getBeanNamesForAnnotation:根据注解获取指定的 BeanName。
  • getBeansWithAnnotation:根据注解获取指定的 BeanName 以及 Bean Map。
  • findAnnotationOnBean:根据指定 beanName 和注解类型查找指定的 Bean。

ListableBeanFactory 有一个实现接口 ConfigurableListableBeanFactory,这是以上所介绍接口的集大成者,ConfigurableListableBeanFactory 继承自 ListableBeanFactory、AutowireCapableBeanFactory 以及 ConfigurableBeanFactory,可以看到,三个二级接口功能集于一身,它包含了 BeanFactory 体系目前的所有方法。这些方法都在 DefaultListableBeanFactory 中进行实现,也就是我们前面所讲的 Spring 源码第六弹!松哥和大家聊聊容器的始祖 DefaultListableBeanFactory。

这就是直接继承自 BeanFactory 的三个接口。

感谢各位的阅读,以上就是“Spring容器怎么配置”的内容了,经过本文的学习后,相信大家对Spring容器怎么配置这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是创新互联,小编将为大家推送更多相关知识点的文章,欢迎关注!


文章名称:Spring容器怎么配置
地址分享:
http://shouzuofang.com/article/gopjop.html

其他资讯