Unable to autowire dependencies into WebApplicationInitializer - spring

I have an existing Spring web service with a web.xml file and a combination of xml-config and java-config. (Primarily xml config because my coworkers still think it's 2009.)
I'm trying to add a dynamic filter registration based on properties. Namely, if a particular boolean property is set, it needs to add one kind of filter, and if it's not set, it'll add a different filter.
I'm trying to do this by implementing WebApplicationInitializer.
The implementation looks like this:
#Configuration
#EnableWebMvc
#ComponentScan(basePackageClasses=Foo.class)
#PropertySource("classpath:svc.properties")
public class WebConfig implements WebApplicationInitializer {
#Value("${dev.mode:false}")
private boolean isDevMode;
#Autowired
Foo foo;
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
// use the web.xml as the base
XmlWebApplicationContext appContext = new XmlWebApplicationContext();
appContext.setConfigLocation("/WEB-INF/web.xml");
if(isDevMode) {
FilterRegistration.Dynamic filterRegistration = servletContext.addFilter("jwtFilter", devModeFilter());
filterRegistration.addMappingForUrlPatterns(null,true,"/blah/*");
} else {
FilterRegistration.Dynamic filterRegistration = servletContext.addFilter("jwtFilter", jwtFilter());
filterRegistration.addMappingForUrlPatterns(null, true, "/blah/*");
}
}
#Bean
public DevModeFilter devModeFilter() {
DevModeFilter filter = new DevModeFilter(foo);
// config here
return filter;
}
#Bean
public DevModeFilter jwtFilter() {
JwtFilter filter = new JwtFilter(foo);
// config here
return filter;
}
}
The filter registration is working -- I can put breakpoints into it and it works great.
The problem is that foo is always null, and the #Value annotated property always takes the default value. (Foo is a bean, annotated with #Component with an autowired constructor that as a parameter an instance of another bean that's declared in an #Bean elsewhere in the app.) I can put breakpoints both in the filters themselves and in the onStartup method and they trigger as expected, right up to the point where they need to interact with foo (which is always null).
The web.xml is normal and otherwise functions. It does declare the contextConfigLocation of the spring xml config files in it, which have the appropriate <context:component-scan />, <context:annotation-config />, <mvc:annotation-driven />, configs etc.
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="FooApp" version="3.0">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/service-base.xml</param-value>
</context-param>
<!-- listeners, servlets, and filters config'd here -->
</web-app>
How can I get my properties file and autowired dependency here so I can register a (spring bean) filter dynamically? I realize that this is probably due to my use of WebApplicationInitializer, which is managed by the servlet and not by Spring, but I'm having difficulties finding Spring-based alternatives.
I'm not allowed to use Spring-Boot or profiles. (Policy, not my own personal decision.)

Related

What exactly is the ResourceConfig class in Jersey 2?

I have seen a lot of Jersey tutorials that starts with something like
#ApplicationPath("services")
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
packages("com.abc.jersey.services");
}
}
without explaining what exactly the ResourceConfig class is. So where can I find its documentation, usage, etc.? Googling for "jersey resourceconfig" does not yield any official doc.
Some of my questions about this class and its usage are:
What things can I do inside the subclass of ResourceConfig?
Do I need to register the subclass of ResourceConfig somewhere so that it can be found or is it automatically detected by Jersey?
If the subclass is automatically detected what happens if I have multiple subclasses of ResourceConfig?
Is the purpose of ResourceConfig the same as the web.xml file? If so what happens if I have both in my project? Does one of them take precedence over the other?
Standard JAX-RS uses an Application as its configuration class. ResourceConfig extends Application.
There are three main ways (in a servlet container) to configure Jersey (JAX-RS):
With only web.xml
With both web.xml and an Application/ResourceConfig class
With only an Application/ResourceConfig class annotated with #ApplicationPath.
With only web.xml
It is possible to configure the application in a standard JAX-RS way, but the following is specific to Jersey
<web-app>
<servlet>
<servlet-name>jersey-servlet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.mypackage.to.scan</param-value>
</init-param>
</servlet>
...
<servlet-mapping>
<servlet-name>jersey-servlet</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
...
</web-app>
Since Jersey runs in a servlet container, it is only right that the Jersey application runs as a servlet. The Jersey Servlet that handles incoming requests is the ServletContainer. So here we declare it as the <servlet-class>. We also configure an <init-param> telling Jersey which package(s) to scan for our #Path and #Provider classes so it can register them.
Under the hood, Jersey will actually create a ResourceConfig instance, as that's what it uses to configure the application. Then it will register all the classes that it discovers through the package scan.
With both web.xml and Application/ResourceConfig
If we want to programmatically configure our application with an Application or ResourceConfig subclass, we can do so with one change to the above web.xml. Instead of setting an init-param to scan for packages, we use an init-param to declare our Application/ResourceConfig subclass.
<servlet>
<servlet-name>jersey-servlet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.example.JerseyApplication</param-value>
</init-param>
<servlet-mapping>
<servlet-name>jersey-servlet</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
</servlet>
package com.example;
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
packages("com.abc.jersey.services");
}
}
Here, we configure the init-param javax.ws.rs.Application with the fully qualified name of our ResourceConfig subclass. And instead of using the init-param that tells Jersey which package(s) to scan, we just use the convenience method packages() of the ResourceConfig.
We could also use the methods register() and property() to register resources and providers, and to configure Jersey properties. With the property() method, anything that can be configured as an init-param, can also be configured using the property() method. For instance instead of calling packages(), we could do
public JerseyApplication() {
property("jersey.config.server.provider.packages",
"com.mypackage.to.scan");
}
With only Application/ResourceConfig
Without a web.xml, Jersey needs a way for us to provide the servlet-mapping. We do this with the #ApplicationPath annotation.
// 'services', '/services', or '/services/*'
// is all the same. Jersey will change it to be '/services/*'
#ApplicationPath("services")
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
packages("com.abc.jersey.services");
}
}
Here with the #ApplicationPath, it's just like if we configured the servlet mapping in the web.xml
<servlet-mapping>
<servlet-name>JerseyApplication</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
When using only Java code for configuration, there needs to be some way for Jersey to discover our configuration class. This is done with the use of a ServletContanerInitializer. This is something that was introduced in the Servlet 3.0 Specification, so we cannot use "Java only" configuration in earlier servlet containers.
Basically what happens is that the implementor of the initializer can tell the servlet container what classes to look for, and the servlet container will pass those classes to the initializer onStartup() method. In Jersey's implementation of the initializer, Jersey configures it to look for Application classes and classes annotated with #ApplicationPath. See this post for further explanation. So when the servlet container starts the application, Jersey's initializer will get passed our Application/ResourceConfig class.
What things can I do inside the subclass of ResourceConfig
Just look at the javadoc. Its mostly just registration of classes. Not much else you need to do with it. The main methods you will be using are the register(), packages(), and property() methods. The register() method lets you manually register classes and instances of resources and providers manually. The packages() method, discussed earlier, lists the package(s) you want Jersey to scan for #Path and #Provider classes and register them for you. And the property() method allows you to set some configurable properties 1.
The ResourceConfig is just a convenience class. Remember, it extends Application, so we could even use the standard Application class
#ApplicationPath("/services")
public class JerseyApplication extends Application {
private final Set<Class<?>> classes;
private final Set<Object> singletons;
public JerseyApplication() {
// configure in constructor as Jersey
// may call the getXxx methods multiple times
this.classes = new HashSet<>();
this.classes.add(MyResource.class);
this.singletons = new HashSet<>();
this.singletons.add(new MyProvider());
}
#Override
public Set<Class<?>> getClasses() {
return this.classes;
}
#Override
public Set<Object> getSingletons() {
return this.singletons;
}
#Override
public Map<String, Object> getProperties() {
final Map<String, Object> properties = new HashMap<>();
properties.put("jersey.config.server.provider.packages",
"com.mypackage.to.scan");
return properties;
}
}
With a ResourceConfig, we would just do
public class JerseyApplication extends ResourceConfig {
public JerseyApplication() {
register(MyResource.class);
register(new MyProvider());
packages("com.mypackages.to.scan");
}
}
Aside from being more convenient, there are also a few thing under the hood that help Jersey configure the application.
An SE Environment
All the examples above assume you are running in an installed server environment, e.g. Tomcat. But you can also run the app in an SE environment, where you run an embedded server and start the app from a main method. You will sometimes see these examples when searching around for info, so I want to show what that looks like, so that if you ever do come across this, you are not surprised and know how it differs from your setup.
So sometimes you will see an example like
ResourceConfig config = new ResourceConfig();
config.packages("com.my.package");
config.register(SomeFeature.class);
config.property(SOME_PROP, someValue);
What is most likely happening here is that the example is using an embedded server, like Grizzly. The rest of the code to start the server might be something like
public static void main(String[] args) {
ResourceConfig config = new ResourceConfig();
config.packages("com.my.package");
config.register(SomeFeature.class);
config.property(SOME_PROP, someValue);
String baseUri = "http://localhost:8080/api/";
HttpServer server = GrizzlyHttpServerFactory
.createHttpServer(URI.create(baseUri), config);
server.start();
}
So in this example, there is a standalone server being started and the ResourceConfig is used to configure Jersey. The different here and from previous examples is that in this example, we are not extending the ResourceConfig, but instead just instantiating it. It wouldn't be any different if we were to do
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
packages("com.my.package");
register(SomeFeature.class);
property(SOME_PROP, someValue);
}
}
HttpServer server = GrizzlyHttpServerFactory
.createHttpServer(URI.create(baseUri), new JerseyConfig());
Say you were going through some tutorial and it showed a configuration for a standalone app where they instantiate the ResourceConfig. But you are running your app in an installed servlet container and have been using the earlier configuration where you are extending the ResourceConfig. Well now you know what the difference is and what changes you need to make. I've seen people do some really weird stuff because they didn't understand this difference. For example I saw someone instantiating a ResourceConfig inside a resource class. So this is why I added this extra little piece; so you don't make the same mistake.
Footnotes
1. There are a number of different configurable properties. The link to the ServerProperties are just some general properties. There are also different properties related to specific features. The documentation should mention these properties in the section of the docs related to that feature. For a complete list of all configurable properties, you can look at all the Jersey constants and look for the ones where the string value starts with jersey.config. If you are using a web.xml, then you would use the string value as the init-param param-name. If you are using Java config (ResourceConfig), then you would call property(ServerProperties.SOME_CONF, value)

Spring Cloud Config Client Without Spring Boot

We have an existing spring web app deployed as a WAR file into Amazon Elastic Beanstalk. Currently we load properties files as http resources to give us a single source of property placeholder config resolution. Im investigating replacing this with the new spring cloud configuration server to give us the benefits of git versioning etc.
However the documentation (http://cloud.spring.io/spring-cloud-config/spring-cloud-config.html) only seems to describe a Spring Boot client application. Is it possible to set up the Spring Cloud Config Client in an existing web app? Do I need to manually set up the Bootstrap parent application context etc - are there any examples of this? Our current spring configuration is XML based.
Refrenced: https://wenku.baidu.com/view/493cf9eba300a6c30d229f49.html
Root WebApplicationContext and the Servlet WebApplicationContext uses Environment and initializes PropertySources based on the spring profile. For non-spring boot apps, we need to customize these to get the properties from Config Server and to refresh the beans whenever there is a property change. Below are the changes that needs to happen to get the config working in SpringMVC. You will also need a system property for spring.profile.active
Create a CustomBeanFactoryPostProcessor and set lazyInit on all bean definitions to true to initialize all bean lazily i.e. beans are initialized only upon a request.
#Component
public class AddRefreshScopeProcessor implements BeanFactoryPostProcessor, ApplicationContextAware {
private static ApplicationContext applicationContext;
#SuppressWarnings("unchecked")
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] beanNames = applicationContext.getBeanDefinitionNames();
for(int i=0; i<beanNames.length; i++){
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanNames[i]);
beanDef.setLazyInit(true);
beanDef.setScope("refresh");
}
}
#Override
public void setApplicationContext(ApplicationContext context)
throws BeansException {
applicationContext = context;
}
/**
* Get a Spring bean by type.
*
* #param beanClass
* #return
*/
public static <T> T getBean(Class<T> beanClass) {
return applicationContext.getBean(beanClass);
}
/**
* Get a Spring bean by name.
*
* #param beanName
* #return
*/
public static Object getBean(String beanName) {
return applicationContext.getBean(beanName);
}
}
Create a custom class extending StandardServletEnvironment and overriding the initPropertySources method to load additional PropertySources (from config server).
public class CloudEnvironment extends StandardServletEnvironment {
#Override
public void initPropertySources(ServletContext servletContext, ServletConfig servletConfig) {
super.initPropertySources(servletContext,servletConfig);
customizePropertySources(this.getPropertySources());
}
#Override
protected void customizePropertySources(MutablePropertySources propertySources) {
super.customizePropertySources(propertySources);
try {
PropertySource<?> source = initConfigServicePropertySourceLocator(this);
propertySources.addLast(source);
} catch (
Exception ex) {
ex.printStackTrace();
}
}
private PropertySource<?> initConfigServicePropertySourceLocator(Environment environment) {
ConfigClientProperties configClientProperties = new ConfigClientProperties(environment);
configClientProperties.setUri("http://localhost:8888");
configClientProperties.setProfile("dev");
configClientProperties.setLabel("master");
configClientProperties.setName("YourApplicationName");
System.out.println("##################### will load the client configuration");
System.out.println(configClientProperties);
ConfigServicePropertySourceLocator configServicePropertySourceLocator =
new ConfigServicePropertySourceLocator(configClientProperties);
return configServicePropertySourceLocator.locate(environment);
}
}
Create a custom ApplicatonContextInitializer and override the initialize method to set the custom Enviroment instead of the StandardServletEnvironment.
public class ConfigAppContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.setEnvironment(new CloudEnvironment());
}
}
Modify web.xml to use this custom context initializer for both application context and servlet context.
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextInitializerClasses</param-name>
<param-value>com.my.context.ConfigAppContextInitializer</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>com.my.context.ConfigAppContextInitializer</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
</context-param>
To refresh the beans created a refresh endpoint you will also need to refresh the application Context.
#Controller
public class RefreshController {
#Autowired
private RefreshAppplicationContext refreshAppplicationContext;
#Autowired
private RefreshScope refreshScope;
#RequestMapping(path = "/refreshall", method = RequestMethod.GET)
public String refresh() {
refreshScope.refreshAll();
refreshAppplicationContext.refreshctx();
return "Refreshed";
}
}
RefreshAppplicationContext.java
#Component
public class RefreshAppplicationContext implements ApplicationContextAware {
private ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public void refreshctx(){
((XmlWebApplicationContext)(applicationContext)).refresh();
}
}
I have similar requirement; I have a Web Application that uses Spring XML configuration to define some beans, the value of the properties are stored in .property files. The requirement is that the configuration should be loaded from the hard disk during the development, and from a Spring Cloud Config server in the production environment.
My idea is to have two definition for the PropertyPlaceholderConfigurer; the first one will be used to load the configuration from the hard disk :
<bean id="resources" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" doc:name="Bean">
<property name="locations">
<list>
<value>dcm.properties</value>
<value>post_process.properties</value>
</list>
</property>
</bean>
The second one will load the .properties from the Spring Config Server :
<bean id="resources" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" doc:name="Bean">
<property name="locations">
<list>
<value>http://localhost:8888/trunk/dcm-qa.properties</value>
</list>
</property>
</bean>
Everything that "just works" with Spring Boot is actually no more than some configuration. It's all just a Spring application at the end of the day. So I believe you can probably set everything up manually that Boot does for you automatically, but I'm not aware of anyone actually trying this particular angle. Creating a bootstrap application context is certainly the preferred approach, but depending on your use case you might get it to work with a single context if you make sure the property source locators are executed early enough.
Non Spring (or non Spring Boot) apps can access plain text or binary files in the config server. E.g. in Spring you could use a #PropertySource with a resource location that was a URL, like http://configserver/{app}/{profile}/{label}/application.properties or http://configserver/{app}-{profile}.properties. It's all covered in the user guide.
I found a solution for using spring-cloud-zookeeper without Spring Boot, based on the idea provided here https://wenku.baidu.com/view/493cf9eba300a6c30d229f49.html
It should be easily updated to match your needs and using a Spring Cloud Config Server (the CloudEnvironement class needs to be updated to load the file from the server instead of Zookeeper)
First, create a CloudEnvironement class that will create a PropertySource (ex from Zookeeper) :
CloudEnvironement.java
public class CloudEnvironment extends StandardServletEnvironment {
#Override
protected void customizePropertySources(MutablePropertySources propertySources) {
super.customizePropertySources(propertySources);
try {
propertySources.addLast(initConfigServicePropertySourceLocator(this));
}
catch (Exception ex) {
logger.warn("failed to initialize cloud config environment", ex);
}
}
private PropertySource<?> initConfigServicePropertySourceLocator(Environment environment) {
ZookeeperConfigProperties configProp = new ZookeeperConfigProperties();
ZookeeperProperties props = new ZookeeperProperties();
props.setConnectString("myzookeeper:2181");
CuratorFramework fwk = curatorFramework(exponentialBackoffRetry(props), props);
ZookeeperPropertySourceLocator propertySourceLocator = new ZookeeperPropertySourceLocator(fwk, configProp);
PropertySource<?> source= propertySourceLocator.locate(environment);
return source ;
}
private CuratorFramework curatorFramework(RetryPolicy retryPolicy, ZookeeperProperties properties) {
CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder();
builder.connectString(properties.getConnectString());
CuratorFramework curator = builder.retryPolicy(retryPolicy).build();
curator.start();
try {
curator.blockUntilConnected(properties.getBlockUntilConnectedWait(), properties.getBlockUntilConnectedUnit());
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
return curator;
}
private RetryPolicy exponentialBackoffRetry(ZookeeperProperties properties) {
return new ExponentialBackoffRetry(properties.getBaseSleepTimeMs(),
properties.getMaxRetries(),
properties.getMaxSleepMs());
}
}
Then create a custom XmlWebApplicationContext class : it will enable to load the PropertySource from Zookeeper when your webapplication start and replace the bootstrap magic of Spring Boot:
MyConfigurableWebApplicationContext.java
public class MyConfigurableWebApplicationContext extends XmlWebApplicationContext {
#Override
protected ConfigurableEnvironment createEnvironment() {
return new CloudEnvironment();
}
}
Last, in your web.xml file add the following context-param for using your MyConfigurableWebApplicationContext class and bootstraping your CloudEnvironement.
<context-param>
<param-name>contextClass</param-name>
<param-value>com.kiabi.config.MyConfigurableWebApplicationContext</param-value>
</context-param>
If you use a standard property file configurer, it should still be loaded so you can have properties in both a local file and Zookeeper.
For all this to work you need to have spring-cloud-starter-zookeeper-config and curator-framework jar in your classpath with their dependancy, if you use maven you can add the following to your pom.xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-zookeeper-dependencies</artifactId>
<version>1.1.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-config</artifactId>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
</dependency>
</dependencies>
Posting as an answer because I don't have enough points to comment on Dave Syer's excellent answer. We have implemented his proposed solution in production and it is working as expected. Our newer apps are being written using Boot, while our legacy apps use Spring, but not boot. We were able to use Spring Cloud Config to create a property service that serves properties for both. The changes were minimal. I moved the legacy property files out of the war file to the property service git repository, and changed the property definition from a classpath reference to a URL as Dave describes and inserted our system environment variable just as we did for classpath. It was easy and effective.
<util:properties id="envProperties" location="https://properties.me.com/property-service/services-#{envName}.properties" />
<context:property-placeholder properties-ref="envProperties" ignore-resource-not-found="true" ignore-unresolvable="true" order="0" />
<util:properties id="defaultProperties" location="https://properties.me.com/property-service/services-default.properties" />
<context:property-placeholder properties-ref="defaultProperties" ignore-resource-not-found="true" ignore-unresolvable="true" order="10" />

How to access <context-param> values of web.xml in Spring Controller

I am defining a context-param in web.xml of my application as below
<context-param>
<param-name>baseUrl</param-name>
<param-value>http://www.abc.com/</param-value>
</context-param>
Now i want to use the value of baseUrl in my Controller, so how i can access this.....?
Please tell me if anyone knows about this.
Thanks in advance !
If you are using Spring 3.1+, you don't have to do anything special to obtain the property. Just use the familiar ${property.name} syntax.
For example if you have:
<context-param>
<param-name>property.name</param-name>
<param-value>value</param-value>
</context-param>
in web.xml or
<Parameter name="property.name" value="value" override="false"/>
in Tomcat's context.xml
then you can access it like:
#Component
public class SomeBean {
#Value("${property.name}")
private String someValue;
}
This works because in Spring 3.1+, the environment registered when deploying to a Servlet environment is the StandardServletEnvironment that adds all the servlet context related properties to the ever present Environment.
Make your Controller implement the ServletContextAware interface. This will force you implement a setServletContext(ServletContext servletContext) method and Spring will inject the ServletContext in it. Then just copy the ServletContext reference to a private class member.
public class MyController implements ServletContextAware {
private ServletContext servletContext;
#Override
setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
}
You can get the param-value with:
String urlValue = servletContext.getInitParameter("baseUrl");
First, in your Spring applications "applicationContext.xml" (or whatever you named it:), add a property placeholder like this:
<context:property-placeholder local-override="true" ignore-resource-not-found="true"/>
Optional parameter of "location" could be added if you would also like to load some values found in .properties files. ( location="WEB-INF/my.properties" for example).
The important attribute to remember is the 'local-override="true"' attribute, which tells the place holder to use context parameters if it can't find anything in the loaded properties files.
Then in your constructors and setters you can do the following, using the #Value annotation and SpEL(Spring Expression Language):
#Component
public class AllMine{
public AllMine(#Value("${stuff}") String stuff){
//Do stuff
}
}
This method has the added benefit of abstracting away from the ServletContext, and gives you the ability to override default context-param values with custom values in a properties file.
Hope that helps:)

How to inject jersey filter without adding it web.xml

I dont know if this is possible or not but I have created the Jersey Filter for logging extending the logging filter and I added
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>com.chegg.commons.web.logging.WebRequestLogger</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>com.chegg.commons.web.logging.WebRequestLogger</param-value>
</init-param>
in my web.xml and every thing works fine. I want to take it at one more level. Can servlet container call the filter without the entry in web.xml by any annotation on the top of my logging class. Something like #Aspect. I dont want to use #Aspect as it is not a filter.
Yes you can always use #Provider annotation to annotate your CustomFilterClasses and just register these manually or let jersey scan your filters automatically.
for instance:
package com.test.poc.filters;
#Provider
public class CustomFilter implements ContainerRequestFilter{
#Override
public void filter(ContainerRequestContext requestContext){
//filter logic..
}
}
is one filter which we want to be auto discovered by jersey at runtime so for this we can easily specify one class which extends ResourceConfig
#ApplicationPath("api")
public class CustomResourceConfig extends ResourceConfig{
public CustomResourceConfig(){
super();
packages("com.test.poc.filters;com.test.poc.restservices;com.test.poc.providers");
//ragister any other classes like
//register(JacksonFeature.class);
}
}
This will automatically scan for all the classes annotated with #Provider or #Path in the specified packages

init a spring bean from web.xml

I am updating an existing Java EE web application that uses Spring.
In my web.xml, there is a servlet defined as follows:
<servlet>
<display-name>My Example Servlet</display-name>
<servlet-name>MyExampleServlet</servlet-name>
<servlet-class>com.example.MyExampleServlet</servlet-class>
</servlet>
now, in this class I need to add an #Autowite annotation:
class MyExampleServlet extends HttpServlet {
#Autowired (required = true)
MyExampleBean myExampleBean;
[...]
}
the problem is that MyExampleBean is initialized by the Application Server
(in my case, weblogic.servlet.internal.WebComponentContributor.getNewInstance...)
so, Spring is not aware of that, and Spring does not have a chance to wire "myExampleBean".
How to solve that?
that is, how I need to modify web.xml or MyExampleServlet so that MyExampleServlet gets the reference to myExampleBean?
A possibility would be to add this init code inside MyExampleServlet,
but it requires a reference to servletContext. How to get a reference to servletContext?
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);
myExampleBean = (MyExampleBean) context.getBean("myExampleBean");
I see, HttpServlet/GenericServlet has a getServletContext() method,
(and the application server calls first the servlet's init(ServletConfig config), and config contains a reference to servletContext).
See http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/GenericServlet.html
The code modified:
class MyExampleServlet extends HttpServlet {
MyExampleBean myExampleBean;
#Override
public void init() throws ServletException {
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
myExampleBean = (MyExampleBean) context.getBean("myExampleBean");
}
[...]
}
in your application context xml, you need something like
<bean id="myExampleBean" class="path/to/myExampleBean">

Resources