Opposite of ConditionalOnMissingBean - java

So I have a standard Spring Boot web application. And I have a requirement to allow multiple authentication mechanisms. So I want to be able to have jar files that handle different authentication. One for a SAML server, CAS, OAuth, etc...
I want my "base" war file to use standard jdbc (Which it does now) but I want to be able to put my, say, CAS-security.jar in the classpath and have spring use it's AuthenticationProvider. Right now I have this in my Application.java class
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(authenticationProvider)
.userDetailsService(userDetailsService);
}
And I #Autowire the provider and service, which are defined as #Bean as normal...
But I want to annotate (I think) those #Bean definitions to say "Don't use this if there is another one avail"
I want the exact opposite of ConditionalOnMissingBean. Now I suppose I could use that annotation, and list every possible plugin class that I could use, but that is bad form as I don't want to recompile/redeploy every time I create a new security plugin.
Is there a UseThisIfNoOtherBeanExists type annotation?
In fact, what I really want, is that I have ALL of my security stuff in say, SecurityConfiguration, annotated with #Configuration, and have the whole class replaced with something else if available.

Sounds like you're looking for ConditionalOnMissingBean. A bean annotated with this will only be used if and only if a bean of its type is not already registered in the bean factory.
If you're somehow not satisfied with that, you have options. You can peruse the entire org.springframework.boot.autoconfigure.condition package to see if there's something there that best fits your use case. Alternatively, you could also leverage #Conditional, and hand-craft a condition based on the environment your application is running in.

Related

Order of Configuration in SpringBoot

I am trying to understand how beans that we make using #Configuration tends to override the beans that are generated by SpringBoot by default. I have been working on a project where in many cases we create beans for things like ZuulConfigs and the assumption is, whatever we are making shall take precedence over the default generated bean. I have been trying to figure this out but can't. Basically,
Is Spring achieving this via some custom class loader
If not how is this precedence working. Can I give some precedence in similar manner to my beans
Can I generate similar hierarchy in my project,if so how
The help is highly appreciated
Spring AutoConfiguration is used to provide a basic configuration if certain classes are in the classpath or not.
If you want to configure the order in which beans are instantiated by spring you can use
#DependsOn("A")
public class B {
...
}
This would create bean "A", then "B". Hence you can order the configuration depending upon the beans need first to be done. Anyways Spring automatically detects the dependencies by analyzing the bean classes.
for more help check this question
Spring Boot AutoConfiguration Order
Alternative :
There is also "#AutoConfigureOrder" annotation(where you can prioritise the configuration), you can have a look in the code for deeper understanding.
Documentation of AutoConfiguration is here
First of all, class loading and bean creation are two different things. We don't need to create a bean to load a class, however, a class has to be loaded in order to create a bean.
Now, coming back to Spring's example, Spring looks into all the packages configured by #componentScan and creates beans of all the classes annotated with #Bean, #Configuration and/or #Component. Spring's container keeps track of all the beans created and hence, when it encounters user defined bean with same name and class type as default bean, it replaces the original definition with user defined one (e.g. we can create our custom #ObjectMapper to override Spring boot's own instance). You can also use #Primary annotation to make you bean take precedence if another definition with same class exists (documentation here).
Below are the answers for your questions:
Spring uses reflection to load the classes and create instances. Although you can load the classes with your custom class loader (more on that here), you don't need to worry about it for #Configuration.
Yes, you can use #Primary annotation to give your bean a precedence. You can also use #Order(here) to define the creation order for your beans.
With #Primary, #Order and #Qualifier annotation you can define your own hierarchy for bean creation.
Can I give some precedence in similar manner to my beans
Yes.
A) To define a specific order your Configuration classes will be handled (by the way, a Configuration class does not have to be annotated with #Configuration (so-called full definition), but it's enough to be annotated with #Component, #ComponentScan, #Import, #ImportResource or just have a method annotated with #Bean - so-called lite definition), you should
1) add your Configuration Candidates to your SpringApplication's primarySource, for example, in your main method like that
SpringApplication.run(
new Class[]{YourSpringBootApplication.class, Config1.class, Config2.class, ...},
args);
2) and annotate each of your Configuration Candidates with #Order annotation, any other ordering means like Ordered interface, #DependsOn etc will be ignored by ConfigurationClassPostProcessor, the order in the primarySource array will also be ignored.
Then ConfigurationClassPostProcessor will sort your Configuration Candidates and handle them according the #Order annotation value you specified.
B) The precedence can also be achieved by defining your own AutoConfiguration classes. Although both Configuration and AutoConfiguration are handled by the same ConfigurationClassPostProcessor, they are essentially distinctive machineries. To do so
1) define in your classpath /META-INF/spring.factories file and put in the EnableAutoConfiguration section of it your AutoConfiguration classes like that
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
your.package.AutoConfig1,your.package.AutoConfig2
2) and annotate your AutoConfiguration classes with #AutoConfigureOrder, #AutoConfigureAfter, or #AutoConfigureAfter annotations, any other ordering means again will be ignored.
Like #Strelok pointed out, AutoConfiguration classes, your own and provided e.g. by spring-boot-autoconfigure library alike, will be added to the end of the list of Configuration Candidates.
Remember, however, that the order the Configuration Candidates will be handled by ConfigurationClassPostProcessor does not necessarily coincide with the order the beans defined by the Configuration classes will be created. For example, you might define your Configuration class that overrides TomcatServletWebServerFactory to make your own customization of Tomcat web server like
#Configuration
public class EmbeddedTomcatConfig {
#Bean
public TomcatServletWebServerFactory containerFactory() {
...
return customizedTomcatWebServerFactory;
}
but this method will be called right at the moment when your Spring Boot application decides to create a Web server, regardless of how you defined the precedence for your EmbeddedTomcatConfig Configuration class.
Is Spring achieving this via some custom class loader
There is no need to. Although you could, as always with Spring, define your own ClassLoader for BeanFactory, standard ClassLoader is good enough if everything you need for Configuration in your application is available in the classpath. Please notice, that at first phase ConfigurationClassPostProcessor does not load (i.e. does not resolve) the Configuration candidates classes (otherwise, most of the classes in spring-boot-autoconfigure library will fail to load). Instead it analyzes their annotations with bytecode analyzer, ASM by default. For that purpose, it is just enough to get a binary form, a byte array, of a class to feed it to bytecode analyzer.
Just know this: Spring Boot (specifically) auto configuration classes are always configured last. After all user beans have been created. Spring Boot auto configuration classes almost always use the #ConditionalXXXX annotations to make sure that any beans of the same type/name and other conditions that are configured in your application will take precedence over the Spring Boot auto-configured beans.
If you want your #Component to take precedence over other #Component while scanning all the components by spring, use #Order(Ordered.LOWEST_PRECEDENCE) i.e. the max value to load your component over other.
#Primary is used to give your bean a default preference, we can override the default preference using #Qualifier

What is the equivalent of #DataJpaTest if I just want to test JdbcTemplate code?

Spring Boot 1.4 offers some fantastic testing improvements. One is the #DataJpaTest annotation where it wires up just the parts needed for JPA testing. What would the equivalent look like for just wiring up the parts needed for JdbcTemplate tests?
I'm fine constructing my own composite annotation that mimics the #DataJpaTest one.
Good question. Ironically enough, that one was raised during the testing talk yesterday at SpringOne Platform. Let's see what it takes to implement such dedicated test annotation.
TL;DR check the code on github
First of all you need to create the annotation. This annotation reuses some bits from the spring-boot-test-autoconfigure module. You may want to auto-configure an in-memory database (like DataJpaTest does). You also want to make sure that caching is configured and disabled by default (in case you have #EnableCaching on your Spring Boot application). You also want that all your tests are #Transactional by default so you should add that.
Next, you want that slicing effectively kicks in. All you need at this point is a DataSource, a JdbcTemplate, database migrations (flyway/liquibase) and a transaction manager to process #Transactional. To avoid the other auto-configurations to kick in you should add the following:
#OverrideAutoConfiguration(enabled = false)
Then, you want to explicitly enable the auto-configurations above. In order to do so, you add #ImportAutoConfiguration and you add the following content in META-INF/spring.factories
# AutoConfigureDataJpa auto-configuration imports
com.example.test.autoconfigure.jdbc.DataJdbcTest=\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration
The key in spring.factories should match the FQN of your annotation. Whenever Spring Boot finds #ImportAutoConfiguration with no extra attributes, it will look for a key matching the annotation type in spring.factories.
Next up you want to be able to include additional components (component scan) with a filter. In order to do that, you can add #TypeExcludeFilters(DataJdbcTypeExcludeFilter.class) where DataJdbcTypeExcludeFilter is pretty much the same thing as DataJpaTypeExcludeFilter (so we might want to extract a common class for that).
Once you've done that, you only need to add your annotation and your JdbcTemplate is auto-configured for you
#RunWith(SpringRunner.class)
#DataJdbcTest
public class DataJdbcSampleTests {
#Autowired
private JdbcTemplate jdbcTemplate;
...
}
I think the option will be #JdbcTest, you could found further info on doc.

How do I register beans in camel unit tests that use beans?

I want to unit test single routes configured in java that uses beans. I read in camel in action (chapter 6.1.4) how to do this:
protected RouteBuilder createRouteBuilder() throws Exception {
return new myRoute();
}
But in my case the rout needs some beans to be registered. I know how to register beans in standalone app: see here
But how to register beans within "CamelTestSupport"? Is there a way to use beans without registry? Probably by injecting them (all beans hav no arg constructors)? I am using Guice and in my tests i am using Jukito (Guice+Mockito).
Afer Camel 3.0.0
You can now update the JNDI registry from anywhere you have access to the camel context.
context.getRegistry().bind("myId", myBean);
More info available here https://camel.apache.org/manual/latest/camel-3-migration-guide.html#_camel_test
Before Camel 3.0.0
You need to override the createRegistry() method,
#Override
protected JndiRegistry createRegistry() throws Exception {
JndiRegistry jndi = super.createRegistry();
//use jndi.bind to bind your beans
return jndi;
}
#Test
public void test() {
//perform test
}
No, you cannot use beans without registry.
You need to use the registry to hold the beans instance, otherwise Camel cannot look up the bean for you. You just need to override the createRegistry() method to setup right registry with your beans if your test class extends CamelTestSupport.
The answer provided by #Matthew Wilson is no longer recommended starting with Camel 3.0.0
His solution is still in the ballpark but the implementation details have changed. I have chosen to inject it in setUp (the example is in Kotlin, use your IDE hints to produce the same in Java):
override fun setUp() {
super.setUp()
context.registry.bind("yourBean", YourBean())
}
As you can see, the registry is still involved but now you can only get it from the context. I consider it cleaner to keep these kinds of setup routines in the conveniently named overrideable method setUp. Just don't forget to call the parent version.
If there is a better place to put this kind of routines in, let me know so I can upgrade the answer.
Docs: https://camel.apache.org/manual/latest/camel-3-migration-guide.html

Hard-coded #RequestMapping URL in Spring MVC Controller

I'm studying Spring 3 and I'm using it in a simple web-application.
Now I'm implementing a Spring MVC Controller using annotations, and I'm wondering:
Is there any best practice using #RequestMapping annotation?
I mean: I've seen that usually the URL mapped in this annotation is hardcoded in the class...
Is there a way to pass the URL in a 'loosely coupled way' (to obtain a more reusable class)?
I know that there are some wild cards that can be used, but I think that isn't the solution... Am I wrong?
EDIT:
I add an example to better explain my doubt.
Suppose I want my controller to be triggered by a request to /foo/bar/baz/mypage.htm, in my controller the handler method will be annotated with #RequestMapping("/foo/bar/baz/mypage").
Now I decide to change the URL triggering my controller into /foo/bar/otherpage.htm, so i need to edit my class, put #RequestMapping("/foo/bar/otherpage") on my handler method, recompile the project and deploy it again.
It seems to me not so practical...
Currently annotated controllers aren't very configurable.
As far as I know, the only possible approach to this problem is to use alternative HandlerMappings in order to configure "base URLs" of controllers. For example, as follows:
// Note the absense of #Controller to prevent this controller
// from being discovered by DefaultAnnotationHandlerMapping
public class FooController {
#RequestMapping("/list") public String list(...) { ... }
#ReqeustMapping("/save") public String save(...) { ... }
}
.
<bean
class = "org.springframework.web.servlet.mvc.support.ControllerBeanNameHandlerMapping" />
<bean name = "/foo" class = "FooController" />
<bean name = "/bar" class = "FooController" />
In this example two instances of FooController handle /foo/list, /foo/save, /bar/list and /bar/save respectively.
The upcoming Spring 3.1 will have an improved Spring 3.1 architecture (Spring 3.1 M2: Spring MVC Enhancements) that seems to be more flexible, though I haven't checked it yet.
I think you are trying to solve the wrong problem. If you wanted to change the pages that matched a controller you'd need to change a file somewhere. Would you rather change the file with the related code underneath it, or would you rather work with some XML files that specifies the URL and the class, and then you have to worry about the file being in the right place during runtime?
As there should be almost no code in your controller anyway, you should think of your controllers as compilable configuration files. Also, if you are using a build system like Maven or Ant and not compiling individual files by hand using Javac then compilation time shouldn't be an issue. If it becomes one, it's probably time to split your project into sub-projects.
I think you should just embrace this and see that it is probably not the issue you think it is. Also, did you know that controllers can match to expressions and not just literal strings? That gives you some flexibility in your naming.
If you really want to, you could just fall back to the Spring 2.0 style XML configuration, but I don't think anyone would recommend that.
I think that is not a best practice, but have you tryed with #PathVariable annotations?
#RequestMapping(value="/path/{word}", method=RequestMethod.GET)
public ModelAndView myRestMethod(#PathVariable String word) {
...
}

JMX MXBean Attributes all UNDEFINED - Spring 3.0.x/Tomcat 6.0

I've been trying to get a sample JMX MXBean working in a Spring-configured webapp, but any basic attributes on the MXBean are coming up as UNDEFINED when I connect with jconsole.
Java interface/classes:
public interface IJmxBean { // marker interface for spring config, see below
}
public interface MgmtMXBean { // lexical convention for MXBeans - mgmt interface
public int getAttribute();
}
public class Mgmt implements IJmxBean, MgmtMXBean { // actual JMX bean
private IServiceBean serviceBean; // service bean injected by Spring
private int attribute = 0;
#Override
public int getAttribute() {
if(serviceBean != null) {
attribute = serviceBean.getRequestedAttribute();
}
return attribute;
}
public void setServiceBean(IServiceBean serviceBean) {
this.serviceBean = serviceBean;
}
}
Spring JMX config:
<beans>
<context:component-scan base-package="...">
<context:include-filter type="assignable" expression="...IJmxBean" />
</context:component-scan>
<context:mbean-export />
</beans>
Here's what I know so far:
The element is correctly instantiating a bean named "mgmt". I've got logging in a zero-argument public constructor that indicates it gets constructed.
is correctly automatically detecting and registering the MgmtMXBean interface with my Tomcat 6.0 container. I can connect to the MBeanServer in Tomcat with jconsole and drill down to the Mgmt MXBean.
When examining the MXBean, "Attribute" is always listed as UNDEFINED, but jconsole can tell the correct type of the attribute. Further, hitting "Refresh" in jconsole does not actually invoke the getter method of "Attribute"- I have logging in the getter method to indicate if it is being invoked (similar to the constructor logging that works) and I see nothing in the logs.
At this point I'm not sure what I'm doing wrong. I've tried a number of things, including constructing an explicit Spring MBeanExporter instance and registering the MXBean by hand, but it either results in the MBean/MXBean not getting registered with Tomcat's MBean server or an Attribute value of UNDEFINED.
For various reasons, I'd prefer not to have to use Spring's #ManagedResource/#ManagedAttribute annotations.
Is there something that I'm missing in the Spring docs or MBean/MXBean specs?
ISSUE RESOLVED: Thanks to prompting by Jon Stevens (above), I went back and re-examined my code and Spring configuration files:
Throwing an exception in the getAttribute() method is a sure way to get "Unavailable" to show up as the attribute's value in JConsole. In my case:
The Spring JMX config file I was using was lacking the default-autowire="" attribute on the root <beans> element;
The code presented above checks to see if serviceBean != null. Apparently I write better code on stackoverflow.com than in my test code, since my test code wasn't checking for that. Nor did I have implements InitializingBean or #PostConstruct to check for serviceBean != null like I normally do on almost all the other beans I use;
The code invoking the service bean was before the logging, so I never saw any log messages about getter methods being entered;
JConsole doesn't report when attribute methods throw exceptions;
The NPE did not show up in the Tomcat logs.
Once I resolved the issue with serviceBean == null, everything worked perfectly. Regardless, +1 to Jon for providing a working demo, since there are literally 50 different ways to configure MBeans/MXBeans within Spring.
I've recently built a sample Spring based webapp that very cleanly enables JMX for latest versions of Spring, Hibernate and Ehcache.
It has examples for both EntityManager based access and DAO access (including transactions!). It also shows how to do annotation based injection in order to negate having to use Spring's xml config for beans. There is even a SpringMVC based example servlet using annotations. Basically, this is a Spring based version of a fairly powerful application server running on top of any servlet engine.
It isn't documented yet, but I'll get to that soon. Take a look at the configuration files and source code and it should be pretty clear.
The motivation behind this is that I got tired of all of the crazy blog posts with 50 different ways to set things up and finally made a single simple source that people can work from. It is up on github so feel free to fork the project and do whatever you want with it.
https://github.com/lookfirst/fallback

Categories

Resources