We're building a framework on top of Spring & Spring MVC. Our framework is quite mature at this point - about 2 years old and is used widely within our organization. Our framework is very modular (much like spring itself is). There are various modules that can be used independently or together. When used together they provide many benefits to the end user. We have built a handful custom spring XML namespaces (NamespaceHandlers, BeanDefinitionParsers, etc). Each module provides their own which brings in its own set of XML configuration elements. This is all working great for us and has been a really big win for us.
What we'd like to do now is move away from XML-based configuration and into java config. My idea/thought is for each module to introduce a set of java config annotations that can be used (something similar to the #EnableCaching, #EnableMBeanExport annotations). My question is this - even if I create my annotations - how do I "wire" them in so that if they are present I can do "stuff"? This would be similar conceptually to the NamespaceHandlers & BeanDefinitionParsers. I can't find any documentation anywhere as to how to get started.
I've thought about creating some custom abstract base classes which do what I need them to do - but the problem is when it comes to the end user's application - they can only extend a single class. I need a flexible way for each module in my framework to expose its own custom configuration that end user applications can use, just like they use our XML namespace elements.
Here's a glimpse as to what we do in XML (not full application context file - just a blurb from it pertaining to our custom XML namespaces):
<atom-web:web/>
<atom-web:logging/>
<atom-web:security entitlementsProvider="XML" xmlRefreshInterval="${cache.refresh.interval.ms}"/>
<atom-profile:profile caching="IN_MEMORY" entryExpiryDelay="${cache.refresh.interval.ms}"/>
<atom-prefs:preferences backingStoreUrl="${pref.backingStore.url}"/>
<atom-content:content contentServerBaseUrl="${content.server.url}" contentServerFileUrl="${content.server.file.url}" site="${site.name}" contentTaskExecutor="contentTaskExecutor" snippetCaching="IN_MEMORY" cacheRefreshInterval="${cache.refresh.interval.ms}"/>
<bean id="contentTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor" p:corePoolSize="3" p:maxPoolSize="20"/>
What I'm envisioning is some kind of set of annotations - something like this:
#EnableAtomWebApplication
#EnableAtomWebLogging
#EnableAtomWebSecurity(entitlementsProvider=EntitlementsProvider.XML, xmlRefreshDelay=120000)
#EnableAtomProfile(caching=CachingType.IN_MEMORY, expiryDelay=120000)
// Other annotations for rest of modules
#Configuration
public class ConfigurationClass {
// Rest of configuration in here
}
Any help here would be greatly appreciated. I'm not quite sure where to start and can't really find any documentation anywhere to help me get started.
So after thinking about this a bit I think I've found the correct starting point. I wanted to throw this out there for anyone who might be able to say "yeah thats the right place" or "no you aren't looking in the correct place".
Using my example above
#EnableAtomProfile(caching=CachingType.IN_MEMORY, expiryDelay=120000)
I would create an annotation for the #EnableAtomProfile annotation like this:
#Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
#Target(value={java.lang.annotation.ElementType.TYPE})
#Documented
#Import({AtomProfileBeanDefinitionRegistrar.class})
public #interface EnableAtomProfile {
CachingType caching() default CachingType.NONE;
long expiryDelay default 0;
}
The AtomProfileBeanDefinitionRegistrar class would implement org.springframework.context.annotation.ImportBeanDefinitionRegistrar and do any of the necessary stuff that I'm currently doing in my BeanDefinitionParser
You can have a BeanPostProcessor defined, which would basically:
inspect every single bean created
with reflection check if the object's class is annotated with #YourAnnotation
and if it is, then apply some custom logic - e.g. package the object into some other class or something
Reference:
Spring docs on BeanPostProcessors
source code for RequiredAnnotationBeanPostProcessor, which is a BeanPostProcessor which analyzes annotations
Related
I'm working with the developer of PF4J(Plugin Framework for Java) to provide better plugin functionality for Wicket. There is already a pf4j-spring and a pf4j-wicket project to provide some basic integration. In order to allow the #SpringBean or #Inject annotations to have access to plugin beans in a child context we need to be able to lookup the ApplicationContext associated with a specific class.
So for example, say I have a MyService bean in a child(plugin) ApplicationContext and that plugin also provides a panel that needs that via a #SpringBean annotation. Spring doesn't allow the parent ApplicationContext to see beans in a child context and for good reason. So we would get an exception saying that bean could not be found since #SpringBean only looks up beans in the parent context. We have code that we have developed that look up the child context like so:
SpringPlugin plugin = (SpringPlugin)PluginManager.whichPlugin(MyService.class);
ApplicationContext pluginContext = plugin.getApplicationContext();
How could I modify or provide this functionality in a custom version of SpringComponentInjector? It uses a ISpringContextLocator but that context locator does not specify the class for which it needs the ApplicationContext.
Any ideas on how this could be achieved?
Thanks for your help!
I'm afraid current SpringComponentInjector is not prepared for such usage. You will have to create your own version.
The problem that I see is that you will have to have either as many IComponentInstantiationListeners as plugins there are. Or create a composite ICIL that delegates to SpringBeanLocators for each plugin. I think the composite would be better. Then you'll have to make sure that a Panel in pluginA cannot use a bean located by SpringBeanLocatorB.
If you manage to do it and you find something in wicket-spring that could be made more generic to help make your version simpler then please let us know and we will consider your suggestion(s)!
Take a look at sbp. It is built on top of pf4j to support Spring Boot, and also provides mechanism of sharing beans between main application and plugins. It looks like:
#Override
protected SpringBootstrap createSpringBootstrap() {
return new SharedDataSourceSpringBootstrap(this, MdSimplePluginStarter.class)
.addSharedBeanName("objectMapper")
.addSharedBeanName("cacheService");
}
I am trying to integrate the Activiti-BPM Framework into a Java EE Webapplication.
The main goal at the Moment is, to inject an EJB as DelegateExpression into a Servicetask (to handle Database operations).
I read that Activiti does not (yet) work with EJBs, so i annotated the class like this:
#Named
#LocalBean
#Stateless
#Dependent
public class DatabaseWriter implements JavaDelegate {...}
and try to inject it in multiple ways like this:
activiti:delegateExpression="${DatabaseWriter}"
activiti:delegateExpression="DatabaseWriter"
activiti:delegateExpression="$DatabaseWriter"
respectivley to check if it is just a Bug or something:
activiti:expression="${DatabaseWriter.execute(execution)}"
In any case i get exceptions like "could not resolve DatabaseWriter, no bean foudn that implements JavaDelegate with name DatabseWriter ..."
I tested the Class itself - by not using cdi - JPA does nto work, but the class can be instantiated by Activiti and the execute method is executed - so the class code itself is ok.
I also tried injecting the class in a JAX-RS EJB - both with CDI and #EJB - it works. The problem definetly lies with my way of trying to bring it into Activiti.
I also made a Screenshot of the Problem (all code, xml, and a logmessage) for better understanding, if it helps:
http://s29.postimg.org/tmiknudjb/problem.jpg
Thanks for help or tipps!
Regards,
BillDoor
From the Oracle documentation
Annotating the boundary (Cart) with the #Named annotation makes the
Cart immediately visible for expression language (EL) expressions in
JSP and JSF. This #Named annotation takes the simple name of the
annotated class, puts the first character in lowercase, and exposes it
directly to the JSF pages (or JSP).
Activiti uses same expression language(EL) so my guess is to you try with;
activiti:delegateExpression="${databaseWriter}"
Also, I nevered use EJB and Activiti so I'm just guessing, but upper example is how it works with Spring.
Hope it helps.
How can I configure logging programmatically in a spring boot application?
Using an xml or properties file is not flexible enough for my needs.
Update: I want to achieve something like this:
#Value("${logging.level.root}")
private String loggingLevelRoot;
#Value("${logging.level.myApp}")
private String loggingLevelMyApp;
#Value("${logging.file}")
private boolean fileAppenderEnabled;
....
setLevel(Logger.ROOT_LOGGER_NAME, Level.toLevel(loggingLevelRoot)));
setLevel("com.myapp", Level.toLevel(loggingLevelMyApp)));
setLevel("org.springframework", Level.WARN);
setLevel("org.apache.coyote", Level.INFO);
setLevel("org.apache.catalina", Level.INFO);
setLevel("org.apache.catalina.startup.DigesterFactory", Level.ERROR);
setLevel("org.apache.catalina.util.LifecycleMBeanBase", Level.ERROR);
Logger logger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
logger.addAppender(createConsoleAppender());
if (fileAppenderEnabled) {
logger.addAppender(createFileAppender());
}
All I have per environment is:
logging.level.root=[INFO, DEBUG, ..]
logging.level.myApp=[INFO, DEBUG, ..]
logging.file=[true | false]
No duplication of XML, Groovy and other formats I really don't want to deal with.
At the end of the day, this is really about achieving the same flexibility for logging as Spring JavaConfig did for beans. XML or other file formats are simply too static, require too much duplication and not integrated well enough with the rest of the configuration of the application.
Why should logging be configured differently than any other bean or service? It makes no sense.
I'm not sure you want or need to disable the default XML configuration of the logging system, but you do want to execute your customization calls after that was done. Fortunately that's pretty easy as it's done as early as possible in the initializer chain for a SpringApplication. The easiest place to put your code is probably a SpringApplicationInitializer (it has to implement ApplicationContextInitializer as well so it can be added to the SpringApplication). E.g.
SpringApplication application = new SpringApplication(MySources.class);
application.addInitializers(new LoggingInitializer());
application.run(args);
You won't be able to do dependency injection into the initializer if you do it that way, but it will ensure that it gets called as early as possible in the lifecycle. If your initializer implements EnvironmentAware then you will also be passed an instance of Environment before the call to SpringApplicationInitializer.initialize() - using that you can resolve the environment dependent pieces in your sample, e.g.
String loggingLevelRoot = environment.getProperty("logging.level.root");
Once you have it working, to avoid having to do the same thing for all apps you can make it declarative by adding a META-INF/spring.factories containing your initializer class:
org.springframework.context.ApplicationContextInitializer=\
my.pkg.for.LoggingInitializer
If you really need dependency injection and #Value resolution I think you are going to have to accept that the ApplicationContext will have fully refreshed before you get a chance to configure anything. If that's an acceptable compromise I recommend just adding a LoggingInitializer to your context and have it implement CommandLineRunner.
I'm learning Spring and looking at using Spring Test for my web app (JQuery/CXF/Hibernate). I have been using annotations to wire up my beans and noticed that this sometimes got into the way of polymorphism. For example I have a GenericDAO extended by all DAOs. It is also a concrete class used by simple services, so when I wired it for one of those services, ALL other DAOs became candidates for runtime wiring (because of polymorphism). I could solve that by wiring explicitly by type: #Resource(type= GenericDaoImpl.class), but this goes against the best practice of coding to interfaces ..
Now I want to create unit tests using a MockGenericDaoImpl, and integration tests using GenericDaoImpl. How will I override the annotations? I'm guessing the best approach is to stick to XML-based wiring, so that I can have several versions of beans.xml, one for prod, one for unit tests, one for integration tests, and possibly split them into parallel sub-files, as needed. Isn't this approach more flexible than depending on annotations that either scan to guess the appropriate candidate, or constrain polymorphism?
Can someone give me broad directions on how to organize my test configuration setup? Thank you!
How about using #Configuration class? If you're not familiar with this method - you can declare a class that replaces the XML context file and looks something like this:
#Configuration
#ComponentScan({ "com.project.dao"})
public class TestConfiguration {
#Bean
public GenericDao getGenericDao() {
return new MockGenericDaoImpl();
}
}
In the #ComponentScan annotation just put the relevant packages to scan. This way you're very flexible with the beans you're creating and the way to create them. You can injects mock to the beans whatever way you'd like.
Also you can create several test configurations, each configuration for a different purpose. In order to load the context you need to put this annotation on your test class:
#ContextConfiguration(classes={TestConfiguration .class})
Using XML configuration files prevent you from depending on Spring dependencies. You can replace it with another DI framework(maybe Guice, but this is not realistic for big projects I know). Using XML configuration files enables you to code cleanly.
I hate XML but I hate existence of not-business-logic-specific things in my code more.
I see you know how to overcome the test issues using XML configuration files. I will try to show how to overcome duplication of implementations(one real one mock implementation) problems using annotations.
You can define your beans via annotations. You can select implementation using aliases:
project.dev.properties:
my.project.dao.xDao=xDaoJpaBean
project.test.properties:
my.project.dao.xDao=xDaoMockBean
<alias name="${my.project.dao.xDao}" alias="xDao"/>
#Autowired
#Qualifier("xDao")
protected XDao xDao;
So you can select your implementation just using your properties file. If you want to use Annotations purely you can do this as well:
#Autowired
#Qualifier("${my.project.dao.xDao}")
protected XDao xDao;
Your build environment will specify which properties file to load, in return your bean will be assigned.
Right now I'm exposing the service layer of my application using spring remoting's RMI/SOAP/JMS/Hessian/Burlap/HttpInvoker exporters. What I'd like is to allow the user to somehow define which of these remoting mechanisms they'd like enabled (rather than enabling all of them), then only create those exporter beans.
I was hoping that spring's application context xml's had support for putting in conditional blocks around portions of the xml. However, from what I've seen so far there's nothing in the standard spring distribution that allows you to do something like this.
Are there any other ways to achieve what I'm trying to do?
I am going to assume that you are looking to configure your application based on your environment, as in... for production I want to use this beans, in dev these other ...
As Ralph is saying, since Spring 3.1 you have profiles... But the key, is that you understand that you should put your environment based beans in different configuration files... so you could have something like dev-beans.xml, prod-beans.xml... Then in your main spring file, then you just invoke the appropriate one based on the environment that you are using... So profiles are only technique to do so... But you can also use other techniques, like have a system environmental variable, or pass a parameter in your build to decide which beans you want to use
You could realize this by using a Spring #Configuration bean, so you can construct your beans in java code. (see http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html#beans-java)
#Configuration
public class AppConfig {
#Bean
public MyService myService() {
if ( userSettingIshessian ) {
return new HessianExporter();
}else {
return new BurlapExporter();
}
}
}
Of course you need to get the user setting from somewhere, a system parameter would be easy, or config file, or something else.
Spring 3.1 has the concept of Profiles. My you can use them.