java - 需要一些帮助来理解注释-Spring注释

标签 java spring oop dependency-injection annotations

我正在尝试学习Spring和Hibernate,而且我真的很难理解Annotations及其工作方式。我在Internet上看到的大多数示例都是基于注释的示例,因此在学习Spring或Hibernate之前,我需要首先了解注释的工作方式。

我对它们是什么以及它们的用途有所了解。我知道他们取代了xml配置。 IE。您可以使用注释直接在Java代码中配置bean。我不明白的是如何使用它们以及何时可以使用它们。

试图了解如何做到这一点,我认为如果我看到两者之间的区别,那将是有帮助的。我这里有一个简单的Spring程序。如果要将该示例程序转换为使用批注,我需要做什么?

我之所以要这样做是因为我在下面提供的程序是我非常了解的一个程序(我正在阅读的Spring in Action书中的一个示例)。如果将其转换为注释版本,我将对如何使用注释以及在何处使用注释有所了解。

有什么建议么?

提前致谢

instrumentalist.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-2.0.xsd">

    <bean id="saxophone" class="com.sia.ch1.instrumentalist.Saxophone" />
    <bean id="piano" class="com.sia.ch1.instrumentalist.Piano" />

    <!--  Injecting into bean properties Ken 1 -->
    <bean id="kenny" class="com.sia.ch1.instrumentalist.Instrumentalist">
        <property name="song" value="Jingle Bells"/>
        <property name="instrument" ref="piano"/>       
    </bean> 
</beans>

仪器接口(interface)
package com.sia.ch1.instrumentalist;
public interface Instrument {
    void play();
}

工具实现者
package com.sia.ch1.instrumentalist;

import com.sia.ch1.performer.PerformanceException;
import com.sia.ch1.performer.Performer;

public class Instrumentalist implements Performer{

    private Instrument instrument;
    private String song;

    public Instrumentalist(){}

    public void perform() throws PerformanceException{
        System.out.print("Playing " + song + " : ");        
        instrument.play();
    }

    public void setInstrument(Instrument instrument) {
        this.instrument = instrument;
    }   

    public void setSong(String song) {
        this.song = song;
    }   
}

乐器-钢琴
package com.sia.ch1.instrumentalist;

public class Piano implements Instrument{
    public Piano(){}
    public void play(){
        System.out.println("PLINK PLINK");
    }
}

乐器-萨克斯风
package com.sia.ch1.instrumentalist;

public class Saxophone implements Instrument{
    public Saxophone(){}
    public void play(){
        System.out.println("TOOT TOOT TOOT");
    }
}

主类
package com.sia.ch1.instrumentalist;

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.FileSystemXmlApplicationContext;

    import com.sia.ch1.performer.PerformanceException;
    import com.sia.ch1.performer.Performer;

    public class InstrumentalistApp {

        public static void main(String[] args){
            ApplicationContext ctx = new FileSystemXmlApplicationContext("c:\\projects\\test\\conf\\instrumentalist.xml");

            Performer performer = (Performer) ctx.getBean("kenny");

            try {
                performer.perform();            
            } catch (PerformanceException e) {
                e.printStackTrace();
            }
        }   
    }

异常(exception)
package com.sia.ch1.performer;

public class PerformanceException extends Exception {

    public PerformanceException() {
        super();
        // TODO Auto-generated constructor stub
    }

    public PerformanceException(String message, Throwable cause) {
        super(message, cause);
        // TODO Auto-generated constructor stub
    }

    public PerformanceException(String message) {
        super(message);
        // TODO Auto-generated constructor stub
    }

    public PerformanceException(Throwable cause) {
        super(cause);
        // TODO Auto-generated constructor stub
    }
}

编辑1

为了尝试转换上面的内容,我将通过以下两个简单示例:

范例1:http://jroller.com/habuma/entry/reducing_xml_with_spring_2

范例2:http://www.theserverside.com/tutorial/Spring-Without-XML-The-Basics-of-Spring-Annotations-vs-Spring-XML-Files

我有点理解第一个URL中的示例,但是第二个URL使我有些困惑。在第二个URL的示例中,SummaryConfig类的用途是什么?看来SummaryConfig类是XML文件的Java版本。在第一个示例的示例中未使用此方法。两者有什么区别?

难道是当您使用批注时,您可以将配置详细信息放在Java类中(例如SummaryConfig),也可以如第一个URL中的示例那样将批注放置在bean本身中吗?

谢谢

编辑2

这是我到目前为止所做的

我已经修改了xml文档,以删除配置并启用组件的自动扫描(注意:我更改了已修改版本的程序包名称)
<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-2.5.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <context:component-scan base-package="com.sia.ch1.instrumentalist.annotate" />

</beans>

在钢琴和萨克斯管类中添加了@Component批注。我认为这告诉容器该类应包含在要自动扫描的类中。正确的?
package com.sia.ch1.instrumentalist.annotate;

import org.springframework.stereotype.Component;

@Component
public class Piano implements Instrument{

    public Piano(){}
    public void play(){
        System.out.println("PLINK PLINK");
    }
}

package com.sia.ch1.instrumentalist.annotate;

import org.springframework.stereotype.Component;

@Component
public class Saxophone implements Instrument{
    public Saxophone(){}
    public void play(){
        System.out.println("TOOT TOOT TOOT");
    }
}

这就是我被困住的地方(乐器演奏家课)。
  • 此类中是否需要@Component批注?还是仅在要从另一个类引用该类时才需要?
  • 我知道我需要@Autowire乐器和歌曲属性,但是我如何知道我是否要自动连接名称或类型等
  • 如果在此类中没有表示它的bean,我将如何自动连接String属性?即乐器属性将指代钢琴课,但歌曲属性将自动与之连接?

  • package com.sia.ch1.instrumentalist.annotate;
    //
        import org.springframework.stereotype.Component;
        import com.sia.ch1.performer.PerformanceException;
        import com.sia.ch1.performer.Performer;
        //
            @Component
            public class Instrumentalist implements Performer{
    
            private Instrument instrument;
            private String song;
    
            public Instrumentalist(){}
    
            public void perform() throws PerformanceException{
                System.out.print("Playing " + song + " : ");        
                instrument.play();
            }
    
            public void setInstrument(Instrument instrument) {
                this.instrument = instrument;
            }   
    
            public void setSong(String song) {
                this.song = song;
            }   
        }
    

    我认为我是对的,其他任何类都不需要注释。

    谢谢

    最佳答案

    This is where i am stuck (the Instrumentalist class).

    • Is the @Component annotation required in this class? Or is it only required if the class is to be referenced from another class?


    是的,是的,如果您希望注释扫描从类为您创建Bean,而无需单独的xml配置。由于您在主方法中要求使用Bean名称kenny(按名称,而不是按Instrumentalist类型)的Instrumentalist实现,因此也需要对其进行命名。

    在配置ApplicationContext时,Spring会使用@ Component,@ Repository,@ Controller和@Service注释的类。这四个注释之间的区别是语义上的(区别了类在代码中的作用),它们都做完全相同的事情(除非例如,您有一些仅处理某些注释类型的AOP东西;现在您不这样做)。无需在意)。

    使用任何上述注释对类进行注释与在xml中声明bean相同:
    <bean id="saxophone" class="com.sia.ch1.instrumentalist.Saxophone"> ... </bean>
    

    与...相同
    @Component
    public class Saxophone implements Instrument{
    

    请注意,默认情况下,该bean的名称与该类的名称相同,只是将类名的第一个字母更改为小写(因此@Component public class SomeClass将创建一个名为“someClass”的bean)。

    如果要命名bean,则将名称作为参数提供给注释:
    @Component("kenny")
    public class Instrumentalist implements Performer {
    

    与...相同
     <bean id="kenny" class="com.sia.ch1.instrumentalist.Instrumentalist">
    

    将参数提供给注释的另一种方法是使用@Component(value="kenny")。之所以值= -part是可选的,是因为注释的工作方式如下:如果仅给出一个参数而不告知字段名称,并且注释包含一个名为的字段,则该参数将设置为-字段。如果字段名称是其他名称,或者您要设置注释的多个字段,则需要显式定义以下字段:@SomeAnnotation(field1="some string", field2 = 100)@SomeAnnotation(value="someValue", anotherField="something else")。这一点不重要,但是很高兴知道,因为起初可能会造成混淆。

    因此,@ Component-annotation告诉Spring上下文您想从带注释的类中创建一个bean(或多个bean,请参见@Scope)。当未设置@Scope -annotation时,默认情况下将将这些bean创建为单例(您可以将bean自动连接到多个类,但是它们都看到相同的单个实例)。 For more information about the different scopes, I suggest reading the official documentation

    • I know that i need to @Autowire the instrument and song properties
      but how do i know if i want to autowire byname or bytype etc


    通常,如果只有一个类型(接口(interface))的实现,则按类型 Autowiring 会更方便。在只有一个实现的情况下,按类型进行 Autowiring 是可行的,因为否则Spring不能决定实例和注入(inject)哪个实现。

    在您的情况下,您有两个实现Instrument -interface的不同类:SaxophonePiano。如果尝试按类型自动连接InstrumentInstrumentalist -field,则在Spring构造Instrumentalist -bean时会出现异常:
    Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.sia.ch1.instrumentalist.annotate.Instrument] is defined: expected single matching bean but found 2: [piano, saxophone]
    

    由于有两种Instrument实现,Spring没有足够的信息来确定要在Instrumentalist中注入(inject)哪一种。这就是@Qualifier -annotation介入的地方。使用@Qualifier,您告诉Spring注入(inject)自动连接的依赖项,并使用命名。要在Piano中使用@Qualifier注入(inject)Instrument-Instrumentalist的实现,请执行以下操作:
    @Component(value="kenny")
    public class Instrumentalist implements Performer
    {
        @Autowired
        @Qualifier("piano")
        private Instrument instrument;
    

    与...相同
    <bean id="kenny" class="com.sia.ch1.instrumentalist.Instrumentalist">
        <property name="instrument" ref="piano"/>       
    </bean>
    

    请注意,不需要(但是如果需要的话)可以在@Component("piano") -class中使用Piano,因为默认命名会将类的首字母更改为小写,然后将其用作Bean名称。

    • How would i autowire the String property if in this class there is no bean that represents it? i.e the instrument property would refer to the piano class but what would > the song property be autowired with?


    这是用注释绘制线条的地方(AFAIK);您不能用注解声明String类型的Bean(因为java.lang.String不是接口(interface),无法扩展,因为它是最终的,并且没有接口(interface))。但是,使用xml配置,这是可能的:
    <bean id="songName" class="java.lang.String">   
        <constructor-arg value="Valley of the Queens"/>
    </bean>
    

    您可以混合使用XML和注解,并从注解引用xml中声明的bean,反之亦然,以将该bean注入(inject)Instrumentalistsong -field:
    @Autowired
    @Qualifier("songName")
    private String song;
    

    希望这可以帮助您大致了解Springs的注释并开始使用,我仍然强烈建议您阅读官方文档,因为还有很多其他内容。如果您更喜欢阅读书籍而不是从屏幕上阅读,我建议使用Appress's Spring Recipes(但我敢肯定,还有很多其他好书)。

    关于java - 需要一些帮助来理解注释-Spring注释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8862909/

    相关文章:

    Java - 将对象设置为 null

    java - 如何正确地从 BeanPostProcessor 创建代理?

    java - 在测试中使用 Spring 的 ResourceLoader

    Python 如何从一个方法内部调用另一个方法

    javascript - Prototype 1.7 Object.extend 在原型(prototype)类中使用时无法正常工作

    java - 实例化扩展类或其父类(视情况而定)

    java - 使用多个功能分支时处理架构更改

    java - 如何在 Android 中创建可重用的代码 fragment ?

    java - 如何在回收 View 中隐藏部分字符串?

    Spring 将两个元素添加到 SOAP header