spring中bean管理和bean灌注转载

原创
小哥 3年前 (2022-11-11) 阅读数 46 #大杂烩

1 bean与spring容器的关系

Bean配置信息定义Bean实现和依赖性,Spring各种形式的容器Bean配置信息在容器内建立。Bean定义注册表,然后根据注册表加载并实例化它。Bean,并建立Bean和Bean依赖关系,最后这些都准备好了。Bean放到Bean要调用的外部应用程序的缓存池。

1 bean配置

bean有三种配置方式:

  • 基于xml配置Bean
  • 使用注释定义Bean
  • 基于java类提供Bean定义信息

1.1 基于xml配置Bean

对于基于XML的配置,Spring 2.0以后使用Schema配置的格式使不同类型的配置具有自己的名称空间,这使配置文件更具伸缩性。

(1) 默认命名空间:它没有空间名称。Spring Bean的定义;

②xsi命名空间:此命名空间用于为每个文档指定适当的命名空间。Schema样式文件,是由标准组织定义的标准名称空间;

③aop命名空间:此命名空间为。Spring配置AOP命名空间是用户定义的命名空间。

命名空间定义分为两步:第一步指定命名空间名称;Schema文档样式文件的位置由空格或回车符分隔。

1.1.1 Bean基本配置

在Spring容器的配置文件定义了Bean配置片段如下:

一般来说Spring IOC其中一个容器Bean也就是说,对应的配置文件之一,这种镜像通信应该很容易理解。哪里id为这个Bean通过容器的getBean("foo")相应的Bean,用作容器中的位置查找,是一个外部程序和。Spring IOC容器与桥交互。class属性指定Bean相应的实现类。

以下是基于XML配置文件定义了两个简单的Bean:

<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

 

1.1.2 依赖注入

  1. 属性注入
  2. 构造器注入
  3. 工厂途径注射

1.2 使用注释定义Bean

我们知道,Spring成功启动集装箱的三个主要因素是:Bean定义信息,Bean实现类和Spring它本身如果使用基于XML的配置,Bean定义信息和Bean实现类本身是独立的,Bean定义信息通过Bean在类上实现注释的实现。

下面是使用注释定义一个DAO的Bean:

package com.baobaotao.anno;

import org.springframework.stereotype.Component; import org.springframework.stereotype.Repository; //①通过Repository定义一个DAO的Bean

@Component("userDao") public class UserDao {

}

在(1)中,我们使用@Component注解在UserDao类在类声明中标记,可以是Spring容器标识,Spring容器将自动POJO转换为集装箱管理。Bean。

它和以下内容XML配置等效:

除了@Component以外,Spring提供了3功能基本和@Component等效注释,分别用于DAO、Service及Web层的Controller注释,所以也可以调用这些注释。Bean衍生注释:(类似xml在文件中定义Bean

  • @Repository:用于对DAO实施标签类;
  • @Service:用于对Service实施标签类;
  • @Controller:用于对Controller实施标签类;

你想加入的原因@Component此外,提供这三个特殊注释是为了使注释类本身的使用更加清晰。Spring他们将被赋予一些特殊功能。

1.2.1 从注释配置信息开始spring容器

Spring提供context命名空间,它通过扫描类包以应用注释定义来提供注释定义。Bean的方式:

<?xml version="1.0" encoding="UTF-8" ?>

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"

在(I)声明context命名空间,可在(2)处传递context命名空间component-scan的base-package属性指定需要扫描的基类包,Spring容器将扫描这个基类包中的所有类,并从类中获取注释信息。Bean定义信息。

如果您只想扫描一个特定的类而不是基本包下的所有类,那么可以使用它。resource-pattern属性按如下方式筛选特定类:

< context:component-scan base-package="com.baobaotao" resource-pattern="anno/*.class"/ >

这里我们设置基类包com.baobaotao,默认情况下resource-pattern属性的值为"*/.class",即基类包中的所有类。我们在这里设置"anno/*.class",则Spring仅扫描基本包anno类。

1.3 基于java类提供Bean定义

在普通的POJO只要类被标记@Configuration评论,您可以spring容器提供Bean定义的信息,每个都有标签。@Bean的类方法都相当于提供Bean定义信息。

package com.baobaotao.conf;

import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; //①将一个POJO标记为已定义Bean的配置类 @Configuration public class AppConf { //(2) 以下两种方法定义了两种。Bean,以提供Bean实例化逻辑 @Bean public UserDao userDao(){ return new UserDao();
}

@Bean
public LogDao logDao(){
    return new LogDao();
}
//③定义了logonService的Bean
@Bean
public LogonService logonService(){
    LogonService logonService = new LogonService();
            //(4) 将在(2)和(3)处定义。Bean注入到LogonService Bean中
    logonService.setLogDao(logDao());
    logonService.setUserDao(userDao());
    return logonService;
}

}

①处在APPConf类的定义被标记。@Configuration注意,表示可以使用该类。Spring提供Bean定义信息。类的方法处可以标注@Bean注解,Bean方法的类型由方法的返回值类型决定。默认名称与方法名称相同,也可以由输入显示指定。Bean名称,如@Bean(name="userDao").直接在@Bean以标记方法提供Bean实例化逻辑。

在②处userDao()和logDao()方法定义了UserDao和一个LogDao的Bean,它们的Bean名称分别为userDao和logDao在(iii)中logonService Bean并在(4)处注入在(2)处定义的二者。Bean。

因此,上述配置和以下XML配置时等效:

<bean id="logService" class="com.baobaotao.conf.LogonService" p:logDao-ref="logDao" p:userDao-ref="userDao"/>

基于java如何配置类并基于XML或者基于注释的配置,前者在代码方面更灵活。Bean实例化和Bean程序集,但后两者都是通过配置声明实现的,虽然灵活性稍低,但配置更简单。

2 Bean注入

Bean有两种注射方法,一种是注射。XML中配置,此时分别有属性注入、构造器注入和工厂方法注射;另一种则是使用注释进行注入 @Autowired,@Resource,@Required

2.1 在xml该文件配置依赖项注入。

2.1.1 属性注入

属性注入已完成。setXxx()方法注入Bean属性值或依赖对象,因为属性注入方法具有高选择性和灵活性的优点,所以属性注入是实际应用中最常用的注入方法。

属性注入要求Bean提供默认构造函数,并为需要注入的属性提供相应的构造函数。Setter方法。Spring先调用Bean默认构造函数已实例化。Bean对象,然后由反射调用。Setter方法注入属性值。

package com.baobaotao.anno;

import org.springframework.beans.factory.BeanNameAware;

public class LogonService implements BeanNameAware{

private LogDao logDao;

private UserDao userDao;

public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
}

public void setLogDao(LogDao logDao) {
    this.logDao = logDao;
}

public LogDao getLogDao() {
    return logDao;
}
public UserDao getUserDao() {
    return userDao;
}

public void setBeanName(String beanName) {
    System.out.println("beanName:"+beanName);        
}

public void initMethod1(){
    System.out.println("initMethod1");
}
public void initMethod2(){
    System.out.println("initMethod2");
}

}

bean.xml配置

<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd" default-autowire="byName"

2.1.2 构造方法注入

使用构造器注入的前提是Bean必须提供带参数的构造函数。例如

package com.baobaotao.anno;

import org.springframework.beans.factory.BeanNameAware;

public class LogonService implements BeanNameAware{

public LogonService(){}

public LogonService(LogDao logDao, UserDao userDao) {
    this.logDao = logDao;
    this.userDao = userDao;
}

private LogDao logDao;

private UserDao userDao;

public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
}

public void setLogDao(LogDao logDao) {
    this.logDao = logDao;
}

public LogDao getLogDao() {
    return logDao;
}
public UserDao getUserDao() {
    return userDao;
}

public void setBeanName(String beanName) {
    System.out.println("beanName:"+beanName);        
}

public void initMethod1(){
    System.out.println("initMethod1");
}
public void initMethod2(){
    System.out.println("initMethod2");
}

}

bean.xml配置

<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd" default-autowire="byName">


2.1.3 工厂方法注射

非静态工厂方法:

有些工厂方法是非静态的,即工厂类必须在调用工厂之前实例化。

package com.baobaotao.ditype;

public class CarFactory { public Car createHongQiCar(){ Car car = new Car(); car.setBrand("红旗CA72"); return car; }

public static Car createCar(){ Car car = new Car(); return car; } }

工厂类负责创建一个或多个目标类实例。工厂类方法通常以接口或抽象类变量的形式返回目标类实例。工厂类在外部阻止目标类的实例化步骤,调用方甚至不需要知道特定的目标类是什么。

<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">




静态工厂方法:

许多工厂类是静态的,这意味着用户可以在不创建工厂类实例的情况下调用工厂类方法,因此静态工厂方法比非静态工厂方法更方便。

<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

2.2 使用注释进行注入

2.2.1 使用@Autowired用于自动注射

Spring通过@Autowired注解实现Bean以下是依赖项注入的示例:

package com.baobaotao.anno;

import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; //① 定义一个Service的Bean(中不需要XML中定义Bean) @Service public class LogonService implements BeanNameAware{ //② 分别注入LogDao及UserDao的Bean(中不需要XML中定义property属性注入) @Autowired(required=false) private LogDao logDao; @Autowired @Qualifier("userDao") private UserDao userDao;

public LogDao getLogDao() {
    return logDao;
}
public UserDao getUserDao() {
    return userDao;
}

public void setBeanName(String beanName) {
    System.out.println("beanName:"+beanName);        
}

public void initMethod1(){
    System.out.println("initMethod1");
}
public void initMethod2(){
    System.out.println("initMethod2");
}

}

在(1)中,我们使用@Service将LogonService标记为Bean,在(2),到@Autowired注入LogDao及UserDao的Bean。@Autowired默认情况下,在容器中找到按类型匹配。Bean,当存在且只有一个匹配时Bean时,Spring将其注入@Autowired在标记的变量中。

2.2.2 使用@Autowired的required属性

如果容器中没有与标签变量类型匹配的Bean,Spring容器将在启动时报告。NoSuchBeanDefinitionException例外如果你愿意Spring即使找不到匹配项Bean您不必抛出异常来完成注入,因此可以使用它。@Autowired(required=false)要添加标签:

@Service public class LogonService implements BeanNameAware{ @Autowired(required=false) private LogDao logDao; ... }

默认情况下,@Autowired的required属性的值为true,即需要找到匹配项。Bean,否则将报告异常。

2.2.3 使用@Qualifier指定注入Bean的名称

如果容器中有多个匹配项Bean,你可以通过。@Qualifier注解限定Bean名称如下:

@Service public class LogonService implements BeanNameAware{ @Autowired(required=false) private LogDao logDao; //① 注射命名UserDao,类型为UserDao的Bean @Autowired @Qualifier("userDao") private UserDao userDao; }

这里假设容器有两种类型UserDao的Bean,名为userDao,另一个已命名otherUserDao,则(1)将注入名称。userDao的Bean。

2.2.4 标记类方法

@Autowired您可以标记类成员变量和方法的参数。我们在下面的类方法中使用它们。@Autowired注解:

package com.baobaotao.anno;

import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service;

@Service public class LogonService implements BeanNameAware{

private LogDao logDao;
private UserDao userDao;

@Autowired
public void setLogDao(LogDao logDao) {
    this.logDao = logDao;
}

@Autowired
@Qualifier("userDao")
public void setUserDao(UserDao userDao) {
    System.out.println("auto inject");
    this.userDao = userDao;
}

}

如果方法具有多个参数,Spring自动选择匹配的参数类型Bean注射Spring允许将方法输入参数@Qualifier指定注射Bean名称如下:

@Autowired
public void init(@Qualifier("userDao")UserDao userDao,LogDao logDao){
    System.out.println("multi param inject");
    this.userDao = userDao;
    this.logDao =logDao;
}

在上述示例中,UserDao输入注入名称为userDao的Bean,而LogDao输入注入LogDao类型的Bean。

一般来说在Spring集装箱的体积Bean是单个实例,因此我们通常不必通过@Repository、@Service等注解的value属性为Bean指定名称,无需使用。@Qualifier按名称注射

2.2.5 支持标准注释

此外,Spring还支持@Resource和@Inject注释,这两个标准注释和@Autowired注释的函数类型都是提供类变量和方法输入的自动注入的函数。@Resource请求提供Bean名称的属性(如果该属性为空)将自动在标签处使用变量名或方法名。Bean的名称。

package com.baobaotao.anno;

import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.annotation.Resource;

import org.springframework.stereotype.Component;

@Component public class Boss {

private Car car;

public Boss(){
    System.out.println("construct...");
}

// @Autowired // private void setCar(Car car){ // System.out.println("execute in setCar"); // this.car = car; // }

@Resource("car")
private void setCar(Car car){
    System.out.println("execute in setCar");
    this.car = car;
}

@PostConstruct
private void init1(){
    System.out.println("execute in init1");
}

@PostConstruct
private void init2(){
    System.out.println("execute in init1");
}

@PreDestroy
private void destory1(){
    System.out.println("execute in destory1");
}

@PreDestroy
private void destory2(){
    System.out.println("execute in destory2");
}

}

此时,如果@Resource未指定"car"属性,您还可以根据属性方法获得需要注入的内容。Bean名称看得见的@Autowired按类型的默认匹配注入Bean,@Resource然后按名称匹配注入Bean。而@Inject和@Autowired它也通过类型匹配注入。Bean只是它没有required属性可以看出@Resource还是@Inject注释,无任何功能@AutowiredRich,所以除非必要,你不必在意这两条评论。(类似Xml中使用或者注射,如使用。@Autowired或者Resource等等,这不需要定义。Bean使用属性注入和构造方法时)

2.2.6 关于Autowired和@Resource

1.@Autowired注射按类型注射,只要bean类型和要求bean类型相同,此时注入没有问题。但如果是同一类型bean不止一个,此时注射会出现问题,Spring无法启动容器。
2.@Resourced标签基于bean如果我们不使用该名称,则会注入该名称。@Resource时指定bean姓名,同时Spring容器中没有此名称。bean,这时候@Resource将退化@Autowired也就是说,按类型注入,这可能违反使用。@Resource初衷。因此,建议使用@Resource全部显示名称bean的名字@Resource(name="xxx")

2.2.7 让@Resource和@Autowired生效的几种方法

1.在xml已显式指定配置文件。

2.在xml用于配置文件context:annotation-config 3.在xml用于配置文件context:component-scan 4.重写Spring容器的Context,在自定义BeanFactory时调用AnnotationConfigUtils.registerAnnotationConfigProcessors()将这两个注释处理器添加到容器中。 在使用公司框架之初,我们发现我们可以web层使用@Resource以及@Autowired注射一些bean,首先,这个注释是Spring前提是,我拿出了这部分代码并编写了一个小示例。我发现,如果我想用它,我想用。Spring这两个注释必须直接或间接介绍。AutowiredAnnotationBeanPostProcesso以及CommonAnnotationBeanPostProcessor这两个注释处理器被引入BeanDefinitions中,否则,注入将无法实现,但仔细阅读公司框架代码后,发现没有地方直接或间接介绍这两个注释处理器,并发现公司框架所依赖的一个细节。Spring版本是2.5.6我使用Spring版本是2.5.5最初的结论是高版本的。Spring当容器启动时,两个注释处理器将自动添加到BeanDefinitions在过去的几天里,我仔细研究了它。Spring源代码,发现Spring2.5.6没有这样做。然后写DEBUG在查看了公司框架的源代码之后,我终于发现原来的公司框架有自己的XmlWebApplicationContext,在这个context中重写customizeBeanFactory(),在此方法中调用。AnnotationConfigUtils.registerAnnotationConfigProcessors()该方法将这两个自动注释处理器添加到BeanDefinitions这样公司的框架就在里面了。web层就支持@Resource和@Autowired用于自动注射啦 ![](http://bolinyang.iteye.com/images/smiles/icon_smile.gif) ![](https://www.itfans123.com/wp-content/uploads/2022/11/post-4409-636d3140a0532.gif) // // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.alibaba.citrus.springext.support.context; import com.alibaba.citrus.springext.ResourceLoadingExtendable; import com.alibaba.citrus.springext.ResourceLoadingExtender; import com.alibaba.citrus.springext.support.context.InheritableListableBeanFactory; import com.alibaba.citrus.springext.support.resolver.XmlBeanDefinitionReaderProcessor; import java.io.IOException; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.context.ApplicationListener; import org.springframework.context.annotation.AnnotationConfigUtils; import org.springframework.core.io.Resource; import org.springframework.core.io.support.ResourcePatternResolver; public class XmlWebApplicationContext extends org.springframework.web.context.support.XmlWebApplicationContext implements ResourceLoadingExtendable { private ResourceLoadingExtender resourceLoadingExtender; private boolean parentResolvableDependenciesAccessible = true; public XmlWebApplicationContext() { } public boolean isParentResolvableDependenciesAccessible() { return this.parentResolvableDependenciesAccessible; } public void setParentResolvableDependenciesAccessible(boolean parentResolvableDependenciesAccessible) { this.parentResolvableDependenciesAccessible = parentResolvableDependenciesAccessible; } public void setResourceLoadingExtender(ResourceLoadingExtender resourceLoadingExtender) { if(this.resourceLoadingExtender != null) { this.getApplicationListeners().remove(this.resourceLoadingExtender); } this.resourceLoadingExtender = resourceLoadingExtender; if(resourceLoadingExtender instanceof ApplicationListener) { this.addApplicationListener((ApplicationListener)resourceLoadingExtender); } } protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) { (new XmlBeanDefinitionReaderProcessor(beanDefinitionReader)).addConfigurationPointsSupport(); } protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) { super.customizeBeanFactory(beanFactory);     **//AnnotationConfigUtils.registerAnnotationConfigProcessors()该方法将这两个自动注释处理器添加到BeanDefinitions中,这样,公司的框架就在里面了。web层就支持@Resource和@Autowired用于自动注射** AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory, (Object)null); } protected DefaultListableBeanFactory createBeanFactory() { return (DefaultListableBeanFactory)(this.isParentResolvableDependenciesAccessible()?new InheritableListableBeanFactory(this.getInternalParentBeanFactory()):super.createBeanFactory()); } protected Resource getResourceByPath(String path) { Resource resource = null; if(this.resourceLoadingExtender != null) { resource = this.resourceLoadingExtender.getResourceByPath(path); } if(resource == null) { resource = super.getResourceByPath(path); } return resource; } protected ResourcePatternResolver getResourcePatternResolver() { final ResourcePatternResolver defaultResolver = super.getResourcePatternResolver(); return new ResourcePatternResolver() { public Resource[] getResources(String locationPattern) throws IOException { ResourcePatternResolver resolver = null; if(XmlWebApplicationContext.this.resourceLoadingExtender != null) { resolver = XmlWebApplicationContext.this.resourceLoadingExtender.getResourcePatternResolver(); } if(resolver == null) { resolver = defaultResolver; } return resolver.getResources(locationPattern); } public ClassLoader getClassLoader() { return defaultResolver.getClassLoader(); } public Resource getResource(String location) { return defaultResolver.getResource(location); } }; } }
版权声明

所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除

热门