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

时间:2012-01-14 14:44:08

标签: java spring oop dependency-injection annotations

我正在努力学习Spring和Hibernate,我真的很难理解Annotations以及它们是如何工作的。我在互联网上看到的大部分示例都是基于注释的示例,所以我需要先了解注释如何才能学习Spring或Hibernate

我知道它们是什么以及它们的用途。我知道他们会替换xml配置。即您可以使用注释在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>

乐器主义界面

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();
            }
        }   
    }

异常

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

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

Ex1:http://jroller.com/habuma/entry/reducing_xml_with_spring_2

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

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

当您使用注释时,可以将配置详细信息放在Java类中(例如SummaryConfig),您也可以将注释放在bean本身中,如第一个URL中的示例所示? / p>

谢谢

编辑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注释添加到Piano和Saxophone类中。我认为这告诉容器这个类应该包含在要自动扫描的类中。对?

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;
        }   
    }

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

由于

2 个答案:

答案 0 :(得分:5)

  

这就是我被困的地方(工具主义课)。

     
      
  • 此课程中是否需要@Component注释?或者只是它   如果要从另一个类引用该类,则是必需的吗?
  •   

是的,如果你想让注释扫描从你的类创建bean而没有单独的xml配置。由于您在main方法中要求使用bean名称​​ kenny (按名称,而不是按类型Instrumentalist)进行Instrumentalist - 实现,因此还需要对其进行命名。

使用@ Component,@ Repository,@ Controller和@Service注释的类是Spring在配置ApplicationContext时扫描的类。这四个注释之间的区别是语义的(区分代码中类的作用),它们都做同样的事情(除非你有一些只处理某些注释类型的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") value = -part是可选的原因是因为注释的工作方式如下:如果只给出一个参数而不告诉字段名称,并且注释包含一个名为 value <的字段/ strong>,参数将设置为 -field。如果字段名称是其他名称,或者您想要设置注释的多个字段,则需要明确定义字段:@SomeAnnotation(field1="some string", field2 = 100)@SomeAnnotation(value="someValue", anotherField="something else")。除了这一点之外,这有点了,但是最好知道,因为它最初可能会令人困惑。

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

  
      
  • 我知道我需要@Autowire乐器和歌曲属性
      但我怎么知道我是否想通过名字或类型等自动装配
  •   

通常,如果您只有一个类型(接口)的实现,则按类型自动装配更方便。当只有一个实现时,按类型自动装配工作,因为否则Spring无法决定实例和注入哪个实现。

在您的情况下,您有两个不同的类来实现Instrument - 界面:SaxophonePiano。如果您尝试通过键入Instrument的{​​{1}} - 字段来自动装配,那么当Spring构建Instrumentalist - bean时会出现异常:

Instrumentalist

由于有两个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] - 实现,因此Spring没有足够的信息来确定要在Instrument中注入哪一个。这是@Qualifier注释的步骤。使用@Qualifier,您可以告诉Spring注入自动连接依赖按名称。要使用Instrumentalist中的@Qualifier注入Piano - 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> - 类中不需要(但您可以),因为默认命名会将类的第一个字母更改为小写,然后使用它作为豆名。

  
      
  • 如果在此类中没有bean,我将如何自动装配String属性   代表它?即乐器属性是指钢琴类,但是什么呢?歌曲属性是用?
  • 自动播放的   

这是使用注释绘制线条的地方(AFAIK);你不能用注释声明一个String类型的bean(因为java.lang.String不是一个接口,不能扩展,因为它是最终的,没有接口)。但是,使用xml-configuration,这是可能的:

@Component("piano")

您可以混合和匹配XML和注释,并引用注释中xml声明的bean,反之亦然,将此bean注入Piano s'<bean id="songName" class="java.lang.String"> <constructor-arg value="Valley of the Queens"/> </bean> - 字段:

Instrumentalist

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

答案 1 :(得分:2)

注释可以用作标记接口等标记

class Foo implements java.io.Serializable{
 ...
}

Serializable只是一个标记界面,因此您的应用程序可以了解有关的信息 运行时的类(基本上是通过反射)。

标记接口的问题在于您不能使用它们来标记字段或方法,这就是为什么要引入注释。

假设您有此注释

public @interface myAnnotation{
}

您可以在运行时获取由此标记修饰的方法或字段。

Hibernate和Spring尽可能多的框架需要一些关于你的代码或类的信息,如果你是这些框架的开发者,你将如何实现这一点?当然注释是最好的解决方案(至少是更清洁的方式)

不要将标记接口视为过时。使用标记也有一些优点,因为它们可确保类型安全。

 void M(Serializable s)

除非它实现了Serializable标记,否则你不能将任何对象传递给此方法。有关更多详细信息,请考虑阅读Effective Java那里有一个很好的解释。