だから私はこの質問を見ました:
そして、私の方法がうまくいくかどうか疑問に思っていました。
1)SpringアプリケーションコンテキストでBeanを宣言する
<bean id="dataSource" destroy-method="close" class="org.Apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="initialSize" value="${jdbc.initialSize}" />
<property name="validationQuery" value="${jdbc.validationQuery}" />
<property name="testOnBorrow" value="${jdbc.testOnBorrow}" />
</bean>
<bean id="apiData" class="com.mydomain.api.data.ApiData">
<property name="dataSource" ref="dataSource" />
<property name="apiLogger" ref="apiLogger" />
</bean>
<bean id="apiLogging" class="com.mydomain.api.data.ApiLogger">
<property name="dataSource" ref="dataSource" />
</bean>
2)次のように、サーブレットのinitメソッドをオーバーライドします。
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
this.apiData = (ApiData)ac.getBean("apiData");
this.apiLogger = (ApiLogger)ac.getBean("apiLogger");
}
これは機能しますか、それともSpringはWebアプリケーションの展開のこの時点でサーブレットにBeanを配信する準備ができていませんか? Beanをweb.xml
に入れるなど、もっと伝統的なことをする必要がありますか?
あなたがしようとしていることは、すべての Servlet
が独自の ApplicationContext
インスタンスを持つようにします。たぶんこれはあなたが望むものですが、私はそれを疑います。 ApplicationContext
はアプリケーションに固有でなければなりません。
これを行う適切な方法は、 ApplicationContext
でServletContextListener
をセットアップすることです。
public class SpringApplicationContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
sce.getServletContext().setAttribute("applicationContext", ac);
}
... // contextDestroyed
}
これで、すべてのサーブレットがApplicationContext
属性を介して同じServletContext
にアクセスできます。
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
ApplicationContext ac = (ApplicationContext) config.getServletContext().getAttribute("applicationContext");
this.apiData = (ApiData)ac.getBean("apiData");
this.apiLogger = (ApiLogger)ac.getBean("apiLogger");
}
Sotirios Delimanolisが提供するソリューションを活用したかったのですが、透明な自動配線をミックスに追加しました。この考え方は、プレーンなサーブレットを自動配線対応オブジェクトに変えることです。
そこで、Springコンテキストを取得し、自動配線可能なファクトリを取得して取得し、そのファクトリを使用してサーブレットインスタンス(実際にはサブクラス)を自動配線する親抽象サーブレットクラスを作成しました。また、サブクラスが必要とする場合に備えて、ファクトリーをインスタンス変数として保存します。
したがって、親抽象サーブレットは次のようになります。
public abstract class AbstractServlet extends HttpServlet {
protected AutowireCapableBeanFactory ctx;
@Override
public void init() throws ServletException {
super.init();
ctx = ((ApplicationContext) getServletContext().getAttribute(
"applicationContext")).getAutowireCapableBeanFactory();
//The following line does the magic
ctx.autowireBean(this);
}
}
また、sevletサブクラスは次のようになります。
public class EchoServlet extends AbstractServlet {
@Autowired
private MyService service;
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
response.getWriter().println("Hello! "+ service.getMyParam());
}
}
EchoServletが行う必要があるのは、Springの一般的なプラクティスでBeanを宣言することだけです。魔法は、スーパークラスのinit()メソッドで行われます。
私は徹底的にテストしていません。しかし、Springが管理するプロパティファイルから自動配線されたプロパティも取得するシンプルなBean MyServiceで機能しました。
楽しい!
注:
次のようなSpring独自のコンテキストリスナーを使用して、アプリケーションコンテキストを読み込むのが最善です。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
次に、次のように取得します。
WebApplicationContext context = WebApplicationContextUtils
.getWebApplicationContext(getServletContext());
ctx = context.getAutowireCapableBeanFactory();
ctx.autowireBean(this);
Spring-mvcではなく、spring-webライブラリのみをインポートする必要があります。
ここまでの答えは、これまでのところ私には部分的にしか機能しませんでした。特に@Configurationアノテーションを持つクラスは無視され、xml構成ファイルを使用したくありませんでした。ここでは、Spring(4.3.1)アノテーションベースのセットアップを使用して、インジェクションが正常に機能するようにしたことを示します。
Web-appの下のweb.xmlでAnnotationConfigWebApplicationContextをブートストラップします。パラメーターとして、contextClassとcontextConfigLocation(注釈付きの構成クラス)が必要です。
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.example.config.AppConfig</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
次に、サーブレットのinitメソッドを上書きします。 HttpServletを拡張する抽象クラスを使用するため、すべてのサーブレットで繰り返す必要はありません。
@Configurable
public abstract class MySpringEnabledServlet extends HttpServlet
{
@Override
public void init(
ServletConfig config) throws ServletException
{
super.init(config);
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
[...]
}
そして最後に、web.xmlで言及されているAppConfigクラスにメイン構成があります。
@Configuration
@ComponentScan(basePackages = "com.example")
@Import(
{ SomeOtherConfig.class })
public class AppConfig
{
}
依存クラスには注釈が付けられています。
@Component
public class AnnotatedClassToInject
私のサーブレットの自動配線を介して注入:
@Autowired
private AnnotatedClassToInject myClass;
Springはサーブレットの起動とは無関係です。 SpringがBean xmlを読み取った直後に、Beanを配信する準備が整います。以下のステートメントの直後に、Beanはすでに利用可能です
_ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
_
また、@ LuiggiMendozaが指摘しているように、各ApplicationContext
は独自のBeanを作成/維持するので、ApplicationContext
を作成することは常に適切です一度だけ再利用異なるサーブレットからサーブレットのinit()
メソッド内で作成)