Heim  >  Artikel  >  Java  >  Einführung in die Methoden der Spring Bean-Erweiterungsschnittstelle

Einführung in die Methoden der Spring Bean-Erweiterungsschnittstelle

Y2J
Y2JOriginal
2017-05-11 09:55:001523Durchsuche

In diesem Artikel werden hauptsächlich einige häufig verwendete Spring Bean-Erweiterungsschnittstellen und ihre einfache Verwendung vorgestellt, die einen guten Referenzwert haben. Werfen wir einen Blick darauf mit dem Editor unten

Vorwort

Spring ist ein sehr leistungsfähiges Framework. Man kann sagen, dass fast alle Java-Projekte auf Unternehmensebene Spring verwenden , und Bean ist der Kern des Spring-Frameworks.

Spring Framework verwendet viele Designmuster Im Großen und Ganzen folgt sein Design strikt dem OCP----Öffnungs- und Schließprinzip, das heißt:

1 . Stellen Sie sicher, dass es für Änderungen geschlossen ist, d die von Spring bereitgestellten

abstrakten Klassen

Verwenden Sie Schnittstellen, um das Verhalten beim Laden von Klassen zu ändern Es ist hilfreich, den Spring-Quellcode zu lesen (Sie müssen nicht nachsehen). In jeder Klasse im Detail kann der allgemeine Prozess geklärt werden) Für Einzelpersonen Die Verbesserung des Niveaus ist sehr hilfreich und gleichzeitig können einige ungewöhnliche Spring-Probleme bei der Arbeit entdeckt und gelöst werden. Der Zweck dieses Artikels besteht jedoch nicht darin, den Spring-Prozess zu organisieren, sondern darin, einige häufig verwendete Spring Bean-Toolklassen vorzustellen, damit wir die verschiedenen Funktionen, die Spring den Entwicklern bietet, besser nutzen können begonnen.

InitialingBean und EinwegBean

InitialingBean ist eine Schnittstelle, die eine einzigartige Methode afterPropertiesSet() bereitstellt. DisposableBean ist auch eine Schnittstelle, die eine einzigartige Methode destroy() bereitstellt.

Bei diesen beiden Schnittstellen handelt es sich um einen Satz mit ähnlichen Funktionen, daher werden sie zusammengesetzt: Ersteres ruft, wie der Name schon sagt, die Methode afterPropertiesSet() auf, um einige Initialisierungsarbeiten nach den Bean

-Eigenschaften werden festgelegt. Die Methode destroy() wird aufgerufen, um einige Abschlussarbeiten durchzuführen, bevor der Bean

Lebenszyklus

endet. Schauen wir uns ein Beispiel an, um klar zu wissen, wann die Methode afterPropertiesSet() aufgerufen werden muss, fügen Sie ein Attribut hinzu, geben Sie die Attributsatzmethode an und geben Sie einige Inhalte in der Satzmethode aus:

Konfigurieren Sie eine spring.xml:

Starten Sie den Spring-Container und das Ausführungsergebnis von LifecycleBean ist:
/**
 * @author 五月的仓颉 http://www.cnblogs.com/xrq730/p/5721366.html
 */
public class LifecycleBean implements InitializingBean, DisposableBean
{
  @SuppressWarnings("unused")
  private String  lifeCycleBeanName;

  public void setLifeCycleBeanName(String lifeCycleBeanName)
  {
    System.out.println("Enter LifecycleBean.setLifeCycleBeanName(), lifeCycleBeanName = " + lifeCycleBeanName);
    this.lifeCycleBeanName = lifeCycleBeanName;
  }

  public void destroy() throws Exception
  {
    System.out.println("Enter LifecycleBean.destroy()");
  }

  public void afterPropertiesSet() throws Exception
  {
    System.out.println("Enter LifecycleBean.afterPropertiesSet()");
  }

  public void beanStart()
  {
    System.out.println("Enter LifecycleBean.beanStart()");
  }
  public void beanEnd()
  {
    System.out.println("Enter LifecycleBean.beanEnd()");
  }
}

Das Ausführungsergebnis ist das gleiche wie wir dachten und das afterPropertiesSet ()-Methode ist genau wie der Name schon sagt,
<?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-4.1.xsd">
  
  <bean id="lifeCycleBean" class="org.xrq.bean.lifecycle.LifecycleBean">
    <property name="lifeCycleBeanName" value="lifeCycleBean" />
  </bean>
</beans>

ruft

Enter LifecycleBean.setLifeCycleBeanName(), lifeCycleBeanName = lifeCycleBean
Enter LifecycleBean.afterPropertiesSet()
Enter LifecycleBean.beanStart()
Enter LifecycleBean.destroy()
Enter LifecycleBean.beanEnd()
erst auf, nachdem alle Eigenschaften der

Bean festgelegt wurden. Zu diesen beiden Schnittstellen fasse ich einige Punkte zusammen: 1. Die InitializingBean-Schnittstelle und die Disposible-Schnittstelle können in Verbindung mit der Init-Methode und der Destroy-Methode verwendet werden hat Vorrang vor der Konfiguration

2. Die unterste Ebene der InitializingBean-Schnittstelle und der Disposable-Schnittstelle verwendet

Typ-Methodenname ()

, um direkte Methodenaufrufe durchzuführen unterste Ebene der Init-Methode und der Destroy-Methode

Verwenden Sie Reflection Die letztere entkoppelt Spring, ist aber weniger effizient nach persönlicher Präferenz3. Die afterPropertiesSet()-Methode wird aufgerufen, nachdem die Eigenschaften der Bean festgelegt wurden. Die afterPropertiesSet()-Methode einer bestimmten Bean wird erst ausgeführt, wenn die afterPropertiesSet()-Methode der nächsten Bean festgelegt ist Daher wird nicht empfohlen, in die Methode afterPropertiesSet() zu schreiben, deren Verarbeitung zu lange dauert BeanNameAware, ApplicationContextAware

Diese drei Schnittstellen werden zusammen geschrieben, da sie eine Gruppe sind und ähnliche Funktionen haben.

„Aware“ bedeutet „wahrgenommen“, daher ist die Bedeutung dieser drei Schnittstellen nicht schwer zu verstehen:

1 Beans, die die BeanNameAware-Schnittstelle implementieren, können während des Bean-Ladevorgangs abgerufen werden Die ID der Bean

2. Für Beans, die die ApplicationContextAware-Schnittstelle implementieren, können Sie den ApplicationContext von Spring während des Ladevorgangs der Bean abrufen. Dies ist der Spring-Anwendungskontext ApplicationContext einschließlich Eine große Menge an Spring-Container-Inhalten und -Informationen, einschließlich aller Beans

3. Für eine Bean, die die BeanFactoryAware-Schnittstelle implementiert, kann während des Bean-Ladevorgangs die BeanFactory abgerufen werden, die die Bean lädt

Schauen Sie sich ein Beispiel an:

Konfigurieren Sie eine Spring.xml:

Das Ausführungsergebnis nach dem Starten des Spring-Containers ist:
/**
 * @author 五月的仓颉 http://www.cnblogs.com/xrq730/p/5721366.html
 */
public class AwareBean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware
{
  private String           beanName;

  private ApplicationContext    applicationContext;

  private BeanFactory        beanFactory;

  public void setBeanName(String beanName)
  {
    System.out.println("Enter AwareBean.setBeanName(), beanName = " + beanName + "\n");
    this.beanName = beanName;
  }

  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
  {
    System.out.println("Enter AwareBean.setApplicationContext(), applicationContext = " + applicationContext + "\n");
    this.applicationContext = applicationContext;
  }

  public void setBeanFactory(BeanFactory beanFactory) throws BeansException
  {
    System.out.println("Enter AwareBean.setBeanFactory(), beanfactory = " + beanFactory + "\n");
    this.beanFactory = beanFactory;
  }
}

Über diese drei Schnittstellen und die oben genannten Drucken Sie die Informationen aus und fassen Sie einige Punkte zusammen:
<?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-4.1.xsd">
<bean id="AwareBean" class="org.xrq.bean.aware.AwareBean" />
</beans>

1. Wenn Ihr BeanName, ApplicationContext und BeanFactory nützlich sind, definieren Sie eine

Variable
Enter AwareBean.setBeanName(), beanName = AwareBean

Enter AwareBean.setBeanFactory(), beanfactory = org.springframework.beans.factory.support.DefaultListableBeanFactory@2747fda0: defining beans [AwareBean,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor]; root of factory hierarchy

Enter AwareBean.setApplicationContext(), applicationContext = org.springframework.context.support.GenericApplicationContext@5514cd80: startup date [Mon Aug 08 19:23:30 CST 2016]; root of context hierarchy
, um sie zu speichern. Wenn sie nicht nützlich sind, implementieren Sie einfach die setXXX()-Methode, verwenden Sie einfach die von Spring eingefügten Parameter

2. Wenn die Bean auch InitializingBean implementiert,

stellt der Container sicher, dass BeanName, ApplicationContext und BeanFactory rufen die Methode afterPropertiesSet() auf, die in

FactoryBean injiziert wird

FactoryBean在Spring中是非常有用的,使用Eclipse/MyEclipse的朋友可以对FactoryBean使用ctrl+t查看一下,FactoryBean这个接口在Spring容器中有大量的子实现。

传统的Spring容器加载一个Bean的整个过程,都是由Spring控制的,换句话说,开发者除了设置Bean相关属性之外,是没有太多的自主权的。FactoryBean改变了这一点,开发者可以个性化地定制自己想要实例化出来的Bean,方法就是实现FactoryBean接口。

看一下代码例子,为了讲清楚FactoryBean,内容相对多一些,首先定义一个接口Animal:

public interface Animal
{
  public void move();
}

定义两个实现类Monkey和Tiger:

public class Monkey implements Animal
{
  public void move()
  {
    System.out.println("Monkey move!");
  }
}
public class Tiger implements Animal
{
  public void move()
  {
    System.out.println("Tiger move!");
  }
}

写一个实现类,实现FactoryBean接口:

/**
 * @author 五月的仓颉 http://www.cnblogs.com/xrq730/p/5721366.html
 */
public class AnimalFactoryBean implements FactoryBean<Animal>
{
  private String  animal;

  public Animal getObject() throws Exception
  {
    if ("Monkey".equals(animal))
    {
      return new Monkey();
    }
    else if ("Tiger".equals(animal))
    {
      return new Tiger();
    }
    else
    {
      return null;
    }
  }

  public Class<?> getObjectType()
  {
    return Animal.class;
  }

  public boolean isSingleton()
  {
    return true;
  }
  public void setAnimal(String animal)
  {
    this.animal = animal;
  }
}

配置一个spring.xml,注入属性Tiger:

<?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-4.1.xsd">
  
  <bean id="animal" class="org.xrq.bean.factory.AnimalFactoryBean">
    <property name="animal" value="Tiger"/>
  </bean>  
</beans>

写一个JUnit的测试类:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
    "classpath*:spring.xml",
})
public class BaseTest
{
  @Resource
  private Animal  animal;
  
  @Test
  public void aa()
  {
    animal.move();
  }
}

查看一下运行结果:

Tiger move!

看到最后得到的并不是FactoryBean本身,而是FactoryBean的泛型对象,这就是FactoryBean的作用。FactoryBean的几个方法:

1、getObject()方法是最重要的,控制Bean的实例化过程

2、getObjectType()方法获取接口返回的实例的class

3、isSingleton()方法获取该Bean是否为一个单例的Bean

像我这段代码的功能就是传入一个String类型的参数,可以动态控制生成出来的是接口的哪种子类。有了FactoryBean,同样的我们也可以灵活地操控Bean的生成。

BeanPostProcessor

之前的InitializingBean、DisposableBean、FactoryBean包括init-method和destory-method,针对的都是某个Bean控制其初始化的操作,而似乎没有一种办法可以针对每个Bean的生成前后做一些逻辑操作,PostProcessor则帮助我们做到了这一点,先看一个简单的BeanPostProcessor。

网上有一张图画了Bean生命周期的过程,画得挺好,原图出处:

 

BeanPostProcess接口有两个方法,都可以见名知意:

1、postProcessBeforeInitialization:在初始化Bean之前

2、postProcessAfterInitialization:在初始化Bean之后

值得注意的是,这两个方法是有返回值的,不要返回null,否则getBean的时候拿不到对象。

写一段测试代码,首先定义一个普通的Bean,为了后面能区分,给Bean加一个属性:

public class CommonBean
{
  private String commonName;
  public void setCommonName(String commonName)
  {
    this.commonName = commonName;
  }
  public void initMethod()
  {
    System.out.println("Enter CommonBean.initMethod(), commonName = " + commonName);
  }
}

定义一个PostProcess,实现BeanPostProcess接口:

/**
 * @author 五月的仓颉 http://www.cnblogs.com/xrq730/p/5721366.html
 */
public class PostProcessorBean implements BeanPostProcessor
{
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
  {
    System.out.println("Enter ProcessorBean.postProcessAfterInitialization()\n");
    return bean;
  }
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
  {
    System.out.println("Enter ProcessorBean.postProcessBeforeInitialization()");
    return bean;
  }
}

配置一个spring.xml,给CommonBean的commonName赋予不同的值以区分:

<?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-4.1.xsd">

  <bean id="common0" class="org.xrq.bean.common.CommonBean" init-method="initMethod">
    <property name="commonName" value="common0"/>
  </bean>

  <bean id="common1" class="org.xrq.bean.common.CommonBean" init-method="initMethod">
    <property name="commonName" value="common1"/>
  </bean>
  <bean id="postProcessorBean" class="org.xrq.bean.processor.PostProcessorBean" />
</beans>

运行一个Spring容器, 初始化结果为:

Enter ProcessorBean.postProcessBeforeInitialization()
Enter CommonBean.initMethod(), commonName = common0
Enter ProcessorBean.postProcessAfterInitialization()

Enter ProcessorBean.postProcessBeforeInitialization()
Enter CommonBean.initMethod(), commonName = common1
Enter ProcessorBean.postProcessAfterInitialization()
Enter ProcessorBean.postProcessBeforeInitialization()
Enter ProcessorBean.postProcessAfterInitialization()

看到每个Bean初始化前后都会分别执行postProcessorBeforeInitiallization()方法与postProcessorAfterInitialization()方法,最后两行出现原因是,PostProcessorBean本身也是一个Bean。

BeanFactoryPostProcessor

接下来看另外一个PostProcessor----BeanFactoryPostProcessor。

Spring允许在Bean创建之前,读取Bean的元属性,并根据自己的需求对元属性进行改变,比如将Bean的scope从singleton改变为prototype,最典型的应用应当是PropertyPlaceholderConfigurer,替换xml文件中的占位符,替换为properties文件中相应的key对应的value,这将会在下篇文章中专门讲解PropertyPlaceholderConfigurer的作用及其原理。

BeanFactoryPostProcessor就可以帮助我们实现上述的功能,下面来看一下BeanFactoryPostProcessor的使用,定义一个BeanFactoryPostProcessor的实现类:

/**
 * @author 五月的仓颉 http://www.cnblogs.com/xrq730/p/5721366.html
 */
public class FactoryPostProcessorBean implements BeanFactoryPostProcessor
{
  public void postProcessBeanFactory(ConfigurableListableBeanFactory configurablelistablebeanfactory)
      throws BeansException
  {
    System.out.println("Enter FactoryPostProcessorBean.postProcessBeanFactory()\n");
  }
}

spring.xml里面配置一下这个Bean,就不写了,运行一下Spring容器,结果为:

Enter FactoryPostProcessorBean.postProcessBeanFactory()

Enter ProcessorBean.postProcessBeforeInitialization()
Enter CommonBean.initMethod(), commonName = common0
Enter ProcessorBean.postProcessAfterInitialization()

Enter ProcessorBean.postProcessBeforeInitialization()
Enter CommonBean.initMethod(), commonName = common1
Enter ProcessorBean.postProcessAfterInitialization()
Enter ProcessorBean.postProcessBeforeInitialization()
Enter ProcessorBean.postProcessAfterInitialization()

从执行结果中可以看出两点:

1、BeanFactoryPostProcessor的执行优先级高于BeanPostProcessor

2、BeanFactoryPostProcessor的postProcessBeanFactory()方法只会执行一次

注意到postProcessBeanFactory方法是带了参数ConfigurableListableBeanFactory的,这就和我之前说的可以使用BeanFactoryPostProcessor来改变Bean的属性相对应起来了。ConfigurableListableBeanFactory功能非常丰富,最基本的,它携带了每个Bean的基本信息,比如我简单写一段代码:

/**
 * @author 五月的仓颉 http://www.cnblogs.com/xrq730/p/5721366.html
 */
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurablelistablebeanfactory)
      throws BeansException
{
  BeanDefinition beanDefinition = configurablelistablebeanfactory.getBeanDefinition("common0");
  MutablePropertyValues beanProperty = beanDefinition.getPropertyValues();
  System.out.println("scope before change:" + beanDefinition.getScope());
  beanDefinition.setScope("singleton");
  System.out.println("scope after change:" + beanDefinition.getScope());
  System.out.println("beanProperty:" + beanProperty);
}

看一下执行结果:

scope before change:
scope after change:singleton
beanProperty:PropertyValues: length=1; bean property &#39;commonName&#39;

这样就获取了Bean的生命周期以及重新设置了Bean的生命周期。ConfigurableListableBeanFactory还有很多的功能,比如添加BeanPostProcessor,可以自己去查看。

InstantiationAwareBeanPostProcessor

最后写一个叫做InstantiationAwareBeanPostProcessor的PostProcessor。

InstantiationAwareBeanPostProcessor又代表了Spring的另外一段生命周期:实例化。先区别一下Spring Bean的实例化和初始化两个阶段的主要作用:

1、实例化----实例化的过程是一个创建Bean的过程,即调用Bean的构造函数,单例的Bean放入单例池中

2、初始化----初始化的过程是一个赋值的过程,即调用Bean的setter,设置Bean的属性

之前的BeanPostProcessor作用于过程(2)前后,现在的InstantiationAwareBeanPostProcessor则作用于过程(1)前后,看一下代码,给前面的CommonBean加上构造函数:

public class CommonBean
{
  public CommonBean()
  {
    System.out.println("Enter CommonBean&#39;s constructor");
  }

  private String commonName;

  public void setCommonName(String commonName)
  {
    System.out.println("Enter CommonBean.setCommonName(), commonName = " + commonName);
    this.commonName = commonName;
  }
  public void initMethod()
  {
    System.out.println("Enter CommonBean.initMethod(), commonName = " + commonName);
  }
}

实现InstantiationAwareBeanPostProcessor接口:

/**
 * @author 五月的仓颉 http://www.cnblogs.com/xrq730/p/5721366.html
 */
public class InstantiationAwareBeanPostProcessorBean implements InstantiationAwareBeanPostProcessor
{
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
  {
    System.out.println("Enter InstantiationAwareBeanPostProcessorBean.postProcessAfterInitialization()");
    return bean;
  }

  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
  {
    System.out.println("Enter InstantiationAwareBeanPostProcessorBean.postProcessBeforeInitialization()");
    return bean;
  }

  public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException
  {
    System.out.println("Enter InstantiationAwareBeanPostProcessorBean.postProcessAfterInstantiation()");
    return true;
  }

  public Object postProcessBeforeInstantiation(Class<?> bean, String beanName) throws BeansException
  {
    System.out.println("Enter InstantiationAwareBeanPostProcessorBean.postProcessBeforeInstantiation()");
    return null;
  }
  public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pd, Object bean,
      String beanName) throws BeansException
  {
    return pvs;
  }
}

配置一下spring.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"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">
  
  <bean id="common" class="org.xrq.bean.common.CommonBean">
    <property name="commonName" value="common"/>
  </bean>
  
  <bean class="org.xrq.bean.processor.InstantiationAwareBeanPostProcessorBean" />
</beans>

启动容器,观察一下运行结果为:

Enter InstantiationAwareBeanPostProcessorBean.postProcessBeforeInstantiation()
Enter CommonBean&#39;s constructor
Enter InstantiationAwareBeanPostProcessorBean.postProcessAfterInstantiation()
Enter CommonBean.setCommonName(), commonName = common
Enter InstantiationAwareBeanPostProcessorBean.postProcessBeforeInitialization()
Enter InstantiationAwareBeanPostProcessorBean.postProcessAfterInitialization()
Enter InstantiationAwareBeanPostProcessorBean.postProcessAfterInstantiation()
Enter InstantiationAwareBeanPostProcessorBean.postProcessBeforeInitialization()
Enter InstantiationAwareBeanPostProcessorBean.postProcessAfterInitialization()

最后三行的运行结果不去关注,看到很明显的,InstantiationAwareBeanPostProcessor作用的是Bean实例化前后,即:

1、Bean构造出来之前调用postProcessBeforeInstantiation()方法

2、Bean构造出来之后调用postProcessAfterInstantiation()方法

不过通常来讲,我们不会直接实现InstantiationAwareBeanPostProcessor接口,而是会采用继承InstantiationAwareBeanPostProcessorAdapter这个抽象类的方式来使用。

后记

如果只会写个Bean,配置在xml文件里面,注入一下,那是最最基础的Spring开发者。一个中级、高级的Spring开发者,必然会对Spring中的多个扩展点有所了解,并利用这些扩展点更好地为项目服务,使得整个代码结构更加地优雅,并且可读性、可维护性更好。

【相关推荐】

1. Java免费视频教程

2. JAVA教程手册

3. 全面解析Java注解

Das obige ist der detaillierte Inhalt vonEinführung in die Methoden der Spring Bean-Erweiterungsschnittstelle. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn