I'm using spring-boot 2.3.9 and spring-security with keycloak 12.0.4.
#Configuration
#KeycloakConfiguration
#ConditionalOnProperty("keycloak.enabled")
#Import(KeycloakSpringBootConfigResolver.class)
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true, proxyTargetClass = false) // If I exclude this, no cglib based proxy is created, but #Secured is not applied either
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
And my service bean creation config
#Configuration(proxyBeanMethods = false)
public class EnvironmentConfig {
#Bean
// #Scope(proxyMode = ScopedProxyMode.INTERFACES) // Has no effect
MyServiceInterfaceSecured myService() { new ImplA/ImplB/ImplC() }
}
For some reason spring creates cglib based proxies, which causes other issues (final methods...)
09:56:38.828 DEBUG [,] --- [main] m.DelegatingMethodSecurityMetadataSource : Caching method [CacheKey[example.MyServiceImplA; ...] with attributes [...]
09:57:12.992 INFO [,] --- [main] o.s.a.f.CglibAopProxy : Unable to proxy interface-implementing method [public final java.util.List example.MyServiceImplA.sync()] because it is marked as final: Consider using interface-based JDK proxies instead!
09:57:12.992 DEBUG [,] --- [main] o.s.a.f.CglibAopProxy : Final method [public final java.util.List example.MyServiceImplA.sync()] cannot get proxied via CGLIB: Calls to this method will NOT be routed to the target instance and might lead to NPEs against uninitialized fields in the proxy instance.
TLDR: How do I tell spring to create an interface based proxy for my beans instead of cglib based proxies?
(or which bean/code/log can I check to analyze why it tries to use the cglib proxy)
EDIT: This might be related to spring-cloud-starter-sleuth. If I remove that dependency, everything works as expected. But I also need sleuth.
I fixed it by excluding spring-boot-starter-aop from spring-cloud-starter-sleuth.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</exclusion>
</exclusions>
</dependency>
EDIT: I opened an issue asking for the dependency to be optional or an explanation why it is required:
https://github.com/spring-cloud/spring-cloud-sleuth/issues/1933
Related
I have used this example to implement OptimisticLockException handling:
How to retry JPA transactions after an OptimisticLockException
Dependency in pom.xml:
<dependency>
<groupId>io.hypersistence</groupId>
<artifactId>hypersistence-utils-hibernate-55</artifactId>
<version>${hypersistence-utils.version}</version>
</dependency>
I have annotated the method which may receive OptimisticLockException:
#Retry(times = 10, on = OptimisticLockException.class)
public void modifySomething(){...}
However, when RollbackException/OptimisticLockException/StaleStateException occurs, I get a stack trace, but the method is not retried.
I use it with Guice 4.1.0. Should I bind it somewhere or write the method interceptor?
How to add AOP aspect?
You need to add the RetryAspect to your Spring configuration.
If you are using Guice, you have to create a similar Aspect because the one coming with Hypersistence Utils is only working with Spring.
In Spring, the configuration is very easy; you can do it like this:
#Configuration
#EnableAspectJAutoProxy
#ComponentScan(
basePackages = {
"io.hypersistence.utils.spring.aop"
}
)
public class RetryAspectConfiguration {
}
I am upgrading Spring Boot from 1.3 to 1.5. For upgrading to 1.5 I have replaced
#SpringApplicationConfiguration(classes = TestConfig.class)
#WebIntegrationTest
with
#SpringBootTest(classes = TestConfig.class)
Also, I am using
#Value("${local.server.port}")
protected int port;
to get port number defined in application.properties file. I further use this port number to build a REST URL.
But after the upgrade I am getting the error below whereas the same works fine with 1.3 Spring Boot Test.
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'local.server.port' in value "${local.server.port}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)
Am I missing any changes that I need to do for this to work.
You have to provide a value for webEnvironment. In your case DEFINED_PORT like this
#SpringBootTest(classes = App.class, webEnvironment = WebEnvironment.DEFINED_PORT)
public class YourTest {
#LocalServerPort // shorthand for #Value("${local.server.port}")
private Integer port;
...
}
For details see: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications
Adding another alternate solution which I had elsewhere.
I had configured
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
and
#RunWith(SpringRunner.class)
#SpringBootTest(classes = App.class, webEnvironment = WebEnvironment.RANDOM_PORT)
public class YourTest {
#LocalServerPort // shorthand for #Value("${local.server.port}")
private Integer port;
...
}
Thinking that was it, and still getting this error even when specifying web environment etc. My ${local.server.port} seemed to be always null.
After some time, I noticed that my Spring Boot startup message contained no notion of the port it was using, so apparently it really didn't listen to any port at all - which explained why it was null in the first place. Adding actual container implementation dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
Caused this to appear on my logs:
2019-02-26 18:45:47.231 INFO 12504 --- [ main] o.s.b.web.embedded.jetty.JettyWebServer : Jetty started on port(s) 43132 (http/1.1) with context path '/'
after which local.server.port and #LocalServerPort would also work.
For me the problem was that there was alternative #Configuration class(es) in my other test(s) like this:
#Configuration
public class ReadPropertiesConfiguration {
#Bean
PropertyPlaceholderConfigurer propConfig() {
PropertyPlaceholderConfigurer placeholderConfigurer = new PropertyPlaceholderConfigurer();
placeholderConfigurer.setLocation(new ClassPathResource("application.properties"));
return placeholderConfigurer;
}
}
and #SpringBootApplication of the app was picking that up due to its #ComponentScan, and for some reason it resulted in this problem. When adding exclusion for those and/or replacing them with other solutions things started again to work without problems.
I don't know the root cause why this happens, but that might be your issue as well.
First make sure the property is correctly spelled in the properties file. As i did just few days back using spring-boot-1.5.2 & it works.
Or
You need to add
#PropertySource("classpath:application.properties")
to your class, so it will pick your configurations.
If you need different configurations for test you can add
#TestPropertySource(locations="classpath:test.properties")
Refer #Value not work on Spring Boot Test
I am running a web-app, which has one exposed class ( available to other POJO classes) and that has one autowired private member.
Spring managed class
public class EPSQueueSender {
#Autowired
private AmqpTemplate epsMessageTemplate;
public void dosomething(...){
epsMessageTemplate.convertAndSend(...); // Here epsMessageTemplate is null if instance of EPSQueueSender taken from other POJO
}
}
POJO class
public class Test{
EPSQueueSender sender = new EPSQueueSender();
sender.dosomething(....); // gives null exception on epsMessageTemplate
}
Spring code ( running as WebApp) and POJO class code( different Jar) are on same JVM. The POJO is not able to get initialized autowired object. However it is initialized if I use it in webApp project.
Can someone please give some suggestion how can I overcome this problem?
Last thing I would like to try is to hit webserver as http request from POJO.
beans can be pojo or xml many examples might help. You already have #autowired but you did not create the #bean method itself that belongs in a class annotated with #Configuration
Your problem could be overcome using #Configurable feature of spring. For it you have configure in xml with a code like belove
<context:annotation-config/>
<context:spring-configured/>
<context:load-time-weaver/>
in Java Congiguration like below:
#Configuration
#EnableAspectJAutoProxy
#EnableSpringConfigured
#EnableLoadTimeWeaving
public class ConfigApplicationContext {
}
with this configuration you can benefit of the load-waving aspect technique that througth the build-in Spring bean AnnotationBeanConfigureAspect you can inject Spring bean in a pojo that is annotated with #Configurable. you colud be have a code like below:
#Configurable
public class Test{
#Autowired
private EPSQueueSender sender;
public void method(){
sender.dosomething(....); // gives null exception on epsMessageTemplate
}
}
of course, since that you are using a load-wave technique you have configure an agent that will perform the istruments. the configuration is very simple and you have add a line like below in the start of the jvm or tomcat:
java -javaagent:path of the jar with the agent/spring-instrument.jar
remember of course of insert the aop and spring aop maven dependency:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>yourVersion</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>4
<version>yourVersion</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<version>yourVersion</version>
</dependency>
I hope that this can help you
I want a Feign client to consume a Spring Boot controller, and I want the contract between them to be specified in a common Interface to the degree possible.
The interface with method would look something like this:
#RequestMapping
public interface RuleManager {
#RequestMapping(value = "/addRule", method = RequestMethod.POST, consumes = {"application/json"}, produces = {"application/json"})
#ResponseBody Rule addRule(#RequestBody Rule rule);
}
The Feign client would look like:
#FeignClient(url = "http://localhost:8080")
public interface RuleManagerClient extends RuleManager { }
and the Spring boot controller:
#RestController
public class RuleManagerService implements RuleManager {
#Override
#Transactional
public Rule addRule(#RequestBody Rule rule) {
return rule;
}
}
It's nice that I don't have to specify #RequestMapping in two places, but unfortunately it seems I do have to specify #RequestBody twice. When #RequestBody is omitted from either the controller or the shared interface, the Rule object is instantiated but with all members set to null.
Is there a way around this ? Perhaps this is addressed in a newer version ? My dependencies include:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<exclusions>
<exclusion>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-core</artifactId>
<version>8.14.3</version>
</dependency>
I discovered this technique required at least feign-core 8.6 here:
https://jmnarloch.wordpress.com/2015/08/19/spring-cloud-designing-feign-client/
Thanks for any help.
Apparently this does work--#RequestBody need only appear in the shared Interface. The problem was that I had the following property set in application.properties for the controller but not for the client:
spring.jackson.property-naming-strategy=CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES
That's why the object was instantiated on the server side but with all members null--effectively, the wrong properties were sent across the wire, for example "ruleName" instead of the expected "rule_name".
I have created a web application in spring-boot. I am writing a unit tests with testNG for my business layer.
I have created Application class
#SpringBootApplication
public class TestApplication
{
public static void main(String[] args)
{
SpringApplication.run(TestApplication.class, args);
}
#Bean
Mapper mapper()
{
List<String> mappingFiles = new ArrayList<String>();
mappingFiles.add("dozer-mappings.xml");
return new DozerBeanMapper(mappingFiles);
}
}
My test classes are looks like
#ContextConfiguration(classes = { TestApplication.class })
public class CommissionRuleServiceTest extends AbstractTestNGSpringContextTests
{
#InjectMocks
#Autowired
MyService
#Mock
MyDAO;
#BeforeMethod
public void initMock()
{
MockitoAnnotations.initMocks(this);
}
#Test(dataProvider = "....")
......
......
}
When I run project it shows hugh log on console and it takes times say 20.00secs for just few small tests.
Some of statements from log are,
DEBUG o.s.c.i.s.PathMatchingResourcePatternResolver - Searching directory
DEBUG o.s.c.a.ConfigurationClassPostProcessor
DEBUG o.s.c.a.ClassPathBeanDefinitionScanner
DEBUG o.s.c.i.s.PathMatchingResourcePatternResolver
DEBUG o.s.b.f.s.DefaultListableBeanFactory
DEBUG o.a.c.b.converters.ArrayConverter
DEBUG org.dozer.loader.xml.XMLParser
DEBUG org.hibernate.cfg.SettingsFactory
DEBUG o.h.cfg.annotations.CollectionBinder
DEBUG o.h.cfg.annotations.TableBinder
DEBUG o.h.p.w.spi.MetamodelGraphWalker - Visiting attribute path : MyEntity
DEBUG o.s.b.f.s.DefaultListableBeanFactory
DEBUG org.hibernate.SQL
Why it is taking such a "hugh" time? What should I need to do?
The investigation:
The #SpringBootApplication annotation is equivalent to the following annotations with default attributes:
#Configuration - Indicates that the class contains one or more #Bean methods. Plays together with #ComponentScan.
#EnableAutoConfiguration - Will attempt to guess and configure beans that you are likely to need. This might cause some performance penalty depending on your application.
#ComponentScan - Configures component scanning. As the package is not defined, scanning will occur from the package of the class with this annotation.
Without more code it is not possible to give you an accurate guess, but I think most of the performance penalty is caused by Spring Boot initialization.
By default the logging level is set to INFO in Spring Boot, probably you changed that?
Add this to application.properties or any other level you need (TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF)
logging.level.root=WARN
As was said before auto configuration may impact performance.
You can play with excluding some configurations that you don't need.
Here is an example (random set - don't follow blindly)
#SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
ErrorMvcAutoConfiguration.class, SecurityAutoConfiguration.class, SessionAutoConfiguration.class,
ValidationAutoConfiguration.class, ThymeleafAutoConfiguration.class, WebSocketAutoConfiguration.class,
DispatcherServletAutoConfiguration.class, EmbeddedServletContainerAutoConfiguration.class,
JmxAutoConfiguration.class, MultipartAutoConfiguration.class, WebMvcAutoConfiguration.class,
JacksonAutoConfiguration.class, SpringApplicationAdminJmxAutoConfiguration.class,
MessageSourceAutoConfiguration.class, SendGridAutoConfiguration.class, FreeMarkerAutoConfiguration.class,
GroovyTemplateAutoConfiguration.class, DeviceDelegatingViewResolverAutoConfiguration.class,
SitePreferenceAutoConfiguration.class, MustacheAutoConfiguration.class,
PersistenceExceptionTranslationAutoConfiguration.class})
for test classes I would recommend using
#SpringBootTest(classes = TestApplication.class)
also you can exclude Tomcat if you don't need it in your tests
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
and try to give us more details