I am creating a library using spring-boot (v2.1.6.RELEASE) as a starter project that will facilitate as base extension jar responsible for configuring and starting up some of the components based on client project properties file.
The issue I am facing is that if the client project's SpringBoot Application class contains the same package path as library everything works like charm! but when client project contains different package path and includes ComponentScan, it is not able to load or start components from the library.
Did anyone encounter this issue? how to make client application to auto-configure some of the components from library jar?
Note: I am following the library creation example from here: https://www.baeldung.com/spring-boot-custom-starter
There are many things that can go wrong here, without seeing relevant parts of actual code its hard to tell something concrete. Out of my head, here are a couple of points for consideration that can hopefully lead to the solution:
Since we use starters in our applications (and sometimes people use explicit component scanning in there spring applications) and this obviously works, probably the issue is with the starter module itself. Don't think that the fact that the component scan is used alone prevents the starter from being loaded ;)
Make sure the starter is a: regular library and not packaged as a spring boot application (read you don't use spring boot plugin) and have <packaging>jar</packaging> in your pom.xml or whatever you use to build.
Make sure you have: src/main/resources/META-INF/spring.factories file
(case sensitive and everything)
Make sure that this spring.factories file indeed contains a valid reference on your configuration (java class annotated with #Configuration). If you use component scanning in the same package, it will find and load this configuration even without spring factories, in this case, its just kind of another portion of your code just packaged as a separate jar. So this looks especially "suspicious" to me.
Make sure that #Configuration doesn't have #Conditional-something - maybe this condition is not obeyed and the configuration doesn't start. For debugging purposes maybe you even should remove these #Conditional annotations just to ensure that the Configuration starts. You can also provide some logging inside the #Configuration class, like: "loading my cool library".
Related
I am working on creating an internal library/starter for my team that will add support for creating native images, providing all of the hints that our currently unsupported dependencies will need. I really like providing the metadata via code (using RuntimeHintsRegistrar), but there are also certain classes that need to be initialized at build time for whatever reason.
Right now I'm passing the --initialize-at-build-time and the classes to the Spring Boot Maven Plugin via the BP_NATIVE_IMAGE_BUILD_ARGUMENTS, but ideally I'd like to avoid each consuming app having to include this in their own POM's plugin configuration.
I also understand that I can go more low-level and provide the argument inside of the META-INF/native-image directory in a native-image.properties file, but I'm not sure whether that will play nice with the Spring-provided RuntimeHintsRegistrar effectively creating that underneath the covers.
What is the best way to tell native-image the classes that should be initialized at build time without each consuming app having to pass it in their own POM? Also, if I use the GraalVM tracing agent to generate hints, will those hints play nicely with the ones that RuntimeHintsRegistrar generates?
Thanks in advance!
I am trying to do a log4j migration for a legacy application. I made the changes to the configuration files and tested it locally with Tomcat, where the logs were displayed correctly. However when I deploy on WAS, the logging stops.
I checked a lot of pages about the necessary dependencies and the possible problems, but now I feel I'm stuck. Here is what I already tried:
Added the log4j jars manually to the lib/ext directory in WAS (together with commons-logging, I read an article where it helped, although all these jar-s were already present in the ear)
Double checked, that the configuration file is on the classpath and that it's syntax is correct
Added logj42-web dependency
Added the necessary filters in web.xml (Spring version is 3.8, so also the config listener with the config name context-param)
Checked classloader in WAS - it's parent first
Am I missing something?
Any ideas are appreciated. Thank you in advance!
WAS includes its own commons-logging API (that does not utilize Log4j), so bringing your own logger requires a bit of extra class-loader-related config. Typically, that would go something like this:
Put your commons-logging and log4j jars, along with your logging properties files, in some directory (not WAS_HOME/lib/ext) readable by the user running the server.
Create a shared library on the server, with that directory as its class path, and select the "use an isolated class loader" option. Associate that shared library with your application or web module.
Ideally, that should be it. Isolated shared libraries search themselves before delegating to the server's loaders, so your application will "see" the commons-logging/log4j classes in the shared library instead of in the server, and likewise, it should pick up the configuration files from that directory instead of the ones found in the server.
You can also accomplish this same basic thing by leaving all the logging stuff in your WAR or EAR and setting its class loader to parent-last (which causes the class loader to search locally before delegating to the server-level loaders), but that is a bit riskier configuration - if your application includes APIs that are also provided by the server, parent-last class loading increases the possibility of ClassCastExceptions or LinkageErrors.
We are building a Spring-based Java library that has several #Autowired assignments, which pick up #Bean instances from the library path, detected at runtime.
That works great when we test the application directly (with an #SpringBootApplication in the library)
However when we include the library as a dependency in other projects, it does not do the component scan of the library classes, and so the #Autowired injections never happen.
Of course we could tell the application developers to add the library path to their component scan, but that would lead to questions, errors, and frustration.
How can we tell Spring to do a component scan of the library classes, without explicitly including the scan base in the consumer applications?
You could create a configuration in your library which defines the components the library needs. This answer shows something like that.
Another way would be to create your own autoconfiguration. This article in the spring documentation describes how it is working.
I'm having a problem I simply can't get my head around.
I'm creating a jsf application where I (as administrator) can upload a jar file, and that way around update the application.
Through this tutorial: http://docs.oracle.com/javase/tutorial/deployment/jar/jarclassloader.html I have managed to classload the jar file. The first issue is that I can only class load as "Object" and not cast to an other class type. I get a ClassCastException.
JarClassLoader jcl=new JarClassLoader(url);
Class cl= jcl.retreiveClass(jcl.getMainClassName());
Object ob=cl.newInstance(); //I would like to make this a RouteBuilder object instead of Object
Concretely I'm using Apache Camel, where I can add routes to an existing "core" (CamelContext). What's happening is that I have the core of apache camel running in my web app, and I can then add routes runtime. It's a route I want to package as a jar and load into the app runtime (I want to develop and test the route in my local environment, and then afterwords upload it to the production application). A concrete route is just a simple java class that extends RouteBuilder. I want to upload the jar, classLoad (URLClassLoader) the main class (maybe the whole jar? - does that make sense?), and convert it to a RouteBuilder. This seems to be impossible. I have chosen to upload the jar file to a folder outside my war, so that the routes do not get erased when I restart the webapp (is this smart or should this be done in an other way?). Is that a problem regarding name spaces? Furthermore, I haven't been able to find out whether I need to traverse my entire jar file and classload ever single class inside. Any comments on that?
To me it seems like I have some fundamental misconceptions on how extending / updating a java application is done. I simply can't find any good examples/explanations on how to solve my problem and therefore I conclude that I don't get this on a conceptual level.
Could someone elaborate on how to extend a running jsf application (I guess the same issues are relevant in native java apps), explain how to upload and class load a jar at runtime, and how to cast loaded classes to other class types than Object?
Thanks
Lasse
If you are interested in loading Routes without stopping your application you could consider using an OSGi container like Karaf. Karaf provides support for Apache Camel routes out-of-the-box: http://camel.apache.org/karaf.html
All class loading is managed by the OSGi container and you just need to run some commands to update things. I am not sure if this could work with your JSF application but it worths to take a look.
I am trying to build an project in Eclipse (actually I'm using RAD, so basically eclipse, and when I say 'Java EE Project' I mean an 'Enterprise Application Project').
My Enterprise Application Project (the 'EAR' project) has two module projects :
- service
- web
The service project has some stuff in it, all wired up using Spring.
The web project has its own stuff in it, all wired up using Spring. The UI stuff in the web project needs to use the stuff in the service project.
Both projects are included in the EAR project as modules.
The web project lists the 'service' project as a dependent project in the build path, it's checked off for export, and also has it listed as a EE Module Dependency.
I'm having a really hard time to get this working though:
The spring context in the web project is of course what gets loaded when the application is deployed, and it imports the spring config I need from the service project. This seems to be working fine.
When spring tries to instantiate a bean it throws a ClassNotFoundException. On the very first bean.
I tried simply copying the spring config from my service context and pasting it into my web context, but I got the same ClassNotFoundException.
I have tried instantiating an object of that type (the class that spring says cannot be found) in the java controller class in the web project, and it is successful, both at compile time (no compile errors) and at runtime (no exceptions).
So the classes from my service project are not available on the classpath when spring tries to use them.
Any ideas what's going on here and/or what I might be able to do about it?
There is a class loader policy that you should use ParentClass First . That will be managed either through Application.xml or through web.xml . You need to check your xml's then try.
It's a class loader issue.
Since you're using Spring, I'll assume that you don't have EJBs. If that's the case, why do you need an EAR? Deploy the whole thing as a web project, in a single WAR.
Put all your .class and Spring configuration .xml files in WEB-INF/classes. Load the configuration using org.springframework.web.context.ContextLoaderListener.
I seem to have fixed this - I'm not sure exactly what the problem was but there must have been a small typo in my spring config. I decided to just start fresh with a new spring config and when I started building the new one back up things were working fine. There must have been a problem with the old one.
Thanks for the suggestions though.
Unfortunately we're not always able to change project structure. We're working on structures other people have put in place.
I looked into the ParentClassFirst vs ParentClassLast setting - it seems on websphere the ParentClassFirst setting is the default if you don't specify anything, so I'm leaving it without specification to get that functionality.
http://publib.boulder.ibm.com/infocenter/wasinfo/v6r0/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/crun_classload.html