CDI @Qualifier(自定义),@Alternative(替换)

一:自定义注解,@Inject,@Named的使用

@Inject和@Named大家都知道.这篇主要是说自定义注解的使用方式.JBOSS官方有下载的.

总体如图:CDI @Qualifier(自定义),@Alternative(替换)_第1张图片

faces-config.xml是用于配jsf的.beans.xml是用于cdi的(大多时候它的作用是告诉系统,我是用了CDI,也有一些功能需要用到它).

<faces-config version="2.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
      http://java.sun.com/xml/ns/javaee
      http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">

</faces-config>
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
      http://java.sun.com/xml/ns/javaee 
      http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>
POM文件略.

界面很简单,输出2个:

<!DOCTYPE html
        PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>cdi-injection</title>
</head>
<body>
    <div>
        English Hello: #{translation.englishHello} <br /> Spanish Hello: #{translation.spanishHello}
    </div>
</body>
</html>
最终输出图为: CDI @Qualifier(自定义),@Alternative(替换)_第2张图片

页面使用的后台bean:

package org.jboss.as.quickstarts.cdi.injection.backing;

import javax.inject.Inject;
import javax.inject.Named;

import org.jboss.as.quickstarts.cdi.injection.TranslateService;
import org.jboss.as.quickstarts.cdi.injection.qualifier.English;
import org.jboss.as.quickstarts.cdi.injection.qualifier.Spanish;

/**
 * Simple JSF backing bean, demonstrating CDI injection and qualifiers.
 * 简单的JSF backingbean,展示CDI注入和限定符。
 * Also note, this bean has a name different than the default name.
 * 注意Named重新定义了名称.
 * @author Jason Porter
 */
@Named("translation")
public class TranslationBackingBean {

    @Inject
    @Spanish
    private TranslateService spanishTranslateService;

    @Inject
    @English
    private TranslateService englishTranslateService;

    public String getSpanishHello() {
        return spanishTranslateService.hello();
    }

    public String getEnglishHello() {
        return englishTranslateService.hello();
    }
}

@Named和@Inject不多做介绍了.

下面是Service接口:

package org.jboss.as.quickstarts.cdi.injection;

public interface TranslateService {
    String hello();
}

两个实现:

@Spanish
public class SpanishTranslateService implements TranslateService {

    @Override
    public String hello() {
        return "Hola";
    }

}
@English
public class EnglishTranslateService implements TranslateService {

    @Override
    public String hello() {
        return "Hello";
    }

}
现在的疑问就在@English和@西班牙语了.
package org.jboss.as.quickstarts.cdi.injection.qualifier;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.inject.Qualifier;

@Qualifier
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER })
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface English {
}

TranslationBackingBean 中,
@Inject @Spanish private TranslateService spanishTranslateService;
这句话就是说,注入使用的TranslateService实现为:西班牙.

@Spanish需要标注在实现里和注入的地方.

使用@Qualifier注入不同的类型
在CDI中所有的对象和生产者都是限定类型的。如果你没有分配限定类型那么将会使用默认的@Default和@Any。就像一个罪犯在美国,如果没有足够的钱给律师,那么他将会被分配一个限定类型用来识别正确的对象被注入,你可以写自己定制的限定类型。
限定类型能够匹配注入目标和注入源,确保正确的类型被注入。 

元注解是指注解的注解。包括  @Retention @Target @Document @Inherited四种。

@Target:定义注解的作用目标
  • @Target(ElementType.TYPE)   //接口、类、枚举、注解
  • @Target(ElementType.FIELD) //字段、枚举的常量
  • @Target(ElementType.METHOD) //方法
  • @Target(ElementType.PARAMETER) //方法参数
  • @Target(ElementType.CONSTRUCTOR)  //构造函数
  • @Target(ElementType.LOCAL_VARIABLE)//局部变量
  • @Target(ElementType.ANNOTATION_TYPE)//注解
  • @Target(ElementType.PACKAGE) ///包   
  •  由以上的源码可以知道,他的elementType 可以有多个,一个注解可以为类的,方法的,字段的等等
@Document:说明该注解将被包含在javadoc中

@Retention: 定义注解的保留策略

  • @Retention(RetentionPolicy.SOURCE)   //注解仅存在于源码中,在class字节码文件中不包含
  • @Retention(RetentionPolicy.CLASS)     // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
  • @Retention(RetentionPolicy.RUNTIME)  // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
@Inherited:说明子类可以继承父类中的该注解

关于java的注解自定义将重开一篇文章.

二:cdi-@alternative

页面code:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>CDI Alternative Result</title>
</head>
<body>
The injected value is: <%=request.getAttribute("type")%>
</body>
</html>
Servlet:
package org.jboss.as.quickstarts.cdi.alternative;

import java.io.IOException;

import javax.inject.Inject;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/")
public class Demo extends HttpServlet {
    private static final long serialVersionUID = 1L;

    @Inject
    private Tax tax;
    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        try {
            request.setAttribute("type", tax.getRate());
            RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/result.jsp");
            dispatcher.forward(request, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
interface:
package org.jboss.as.quickstarts.cdi.alternative;

public interface Tax {
    String getRate();
}

两个实现:

package org.jboss.as.quickstarts.cdi.alternative;

public class TaxImpl_1 implements Tax {

	@Override
    public String getRate() {
        return "Tax_1 Rate!";
    }
}
package org.jboss.as.quickstarts.cdi.alternative;

import javax.enterprise.inject.Alternative;

@Alternative
public class TaxImpl_2 implements Tax {

	@Override
    public String getRate() {
        return "Tax_2 Rate! To switch back to the default, go to /META-INF/beans.xml and comment out the 'alternatives' tag";
    }

}

注意实现2有@Alternative注解.系统默认输出是taxImpl_1的输出.

如果想输出第二个,只需要在bean.xml中进行配置:

<beans xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee">
    <alternatives>
        <class>org.jboss.as.quickstarts.cdi.alternative.TaxImpl_2</class>
    </alternatives>
    
</beans>

配置后,将输出2的内容.

主要用于多个接口实现在bean.xml中的实时切换.
 
当多个版本的bean来实现不同的目的,在开发过程中,通过注入一个限定或其他版本之间切换.而不必更改源代码的应用程序,可以选择在部署时使用的替代品。
替代方案通常用于以下目的,如:
1.     为了处理客户特定的业务逻辑在运行时确定。
2.     要指定Bean的有效期为一个特定的部署方案,例如,特定国家的销售税的法律时,需要针对具体国家的销售税业务逻辑。
3.     用于测试的模拟版本。


你可能感兴趣的:(CDI,@Qualifier,@alternative)