spring-boot create bean only when action is called - spring-boot

I have some some spring configuration code which creates the spring bean
#Bean
public MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongoDbFactory());
}
In some class I am using like below
#Autowired
private MongoTemplate mongoTemplate ;
Bean in getting created whenever spring is started but due to some some service I want to make sure bean should be created only when action is invoked on the object
like mongoTemplate.save etc

Proxy by CGLIB and lazy-initialization are available.
#Lazy
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongoDbFactory());
}
https://docs.spring.io/spring/docs/5.2.7.RELEASE/spring-framework-reference/core.html#beans-factorybeans-annotations

Related

Could not autowire. No beans of 'InstructionRepository' type found

Trying to create a bean in SpringBoot application, but getting the following error "Could not autowire. No beans of 'InstructionRepository' type found."
InstructionRepository is annotated with #Repository annotation in the jar and is an Interface extending a Spring Data Interface
ScheduleProcessor is a method
When I Try adding the #ComponentScan annotation by passing the base package value, the error goes away BUT, when I boot up the application get the following error
Parameter 0 of constructor in com.xxx.resync.config.AppConfig required a bean of type 'com.xxx.repo.InstructionRepository' that could not be found. Action: Consider defining a bean of type 'com.xxx.repo.InstructionRepository' in your configuration.
#Configuration
#EnableAutoConfiguration
//#ComponentScan(basePackages = {"com.xxx.repo"})
public class AppConfig {
#Value("${pssHttp.connectTimeout:3000}")
private int connectTimeout;
#Bean
public RestTemplate getRestTemplate() {
RestTemplate restTemplate = new RestTemplate();
final HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(connectTimeout);
factory.setReadTimeout(connectTimeout);
restTemplate.setRequestFactory(factory);
return restTemplate;
}
#Bean
public ScheduleUpdater getScheduleUpdater() {
return new ScheduleUpdater(true);
}
#Bean
public ScheduleProcessor scheduleProcessor(InstructionRepository instructionRepository, ScheduleUpdater scheduleUpdater) {
return new ScheduleProcessor(instructionRepository, scheduleUpdater);
}
}
InstructionRepository
#Repository
public interface InstructionRepository extends CouchbaseRepository<Instruction, String> {
}
How can we fix the error and be able to boot up the Spring boot application?
Any suggestions appreciated.
You need to add #EnableCouchbaseRepositories to enable repo building eg to AppConfig.

spring aspect not getting fired on getConnection

I am trying to intercept the getConnection call in spring 3.2.3
#Component
#Aspect
#Order(value = 1)
public class ConnectionAspect {
//#AfterReturning(pointcut = "execution(java.sql.Connection javax.sql.DataSource.getConnection(..))", returning = "connection")
#Around("execution(java.sql.Connection javax.sql.DataSource.getConnection(..))")
public Connection prepare(ProceedingJoinPoint pjp) throws Throwable {
return MyConnectionProxy.newInstance((Connection) pjp.proceed(pjp.getArgs()));
}
}
This aspect does not invoked on calling getConnection .
Is there any mistake in the point cut definition execution(java.sql.Connection javax.sql.DataSource.getConnection(..))
Spring AOP can only advise spring managed beans. If your DataSource instances are not spring managed beans, you won't be able to achieve your goal with Spring AOP.
I would try to solve this issue by creating some kind of delegating proxy around the container provided DataSource, and make it a bean managed by spring. It turns out there's actually a class intended in Spring specifically for this purpose. It's called DelegatingDataSource. You only need to subclass this class, ovverride the getConnection() method (or whichever other method's behavior you need to affect), set it up for delegating to the container provided DataSource, and making it a spring managed bean and you're good to go.
Someting along this example should do it:
#Configuration
public class DataSourceConfiguration {
public static class MySpecialDataSource extends DelegatingDataSource {
public MySpecialDataSource(DataSource delegate) {
super(delegate);
}
#Override
public Connection getConnection() throws SQLException {
return super.getConnection();
}
}
#Bean
public DataSource dataSource(#Autowired DataSource containerDataSource) {
return new MySpecialDataSource(containerDataSource);
}
#Bean(name="containerDataSource")
public JndiObjectFactoryBean containerDataSource() {
JndiObjectFactoryBean factoryBean = new JndiObjectFactoryBean();
factoryBean.setJndiName("jdbc/MyDataSource");
return factoryBean;
}
}
The best thing is that you didn't even need Spring AOP or AspectJ for that.

"No bean named 'cassandraTemplate' available"

I have not added cassandra template bean in my beandefinition class, but it works fine and gives me the required output while running, but while writing junit test class
it is throwing me a error "No bean named 'cassandraTemplate' available".
Why is this issue raising during running my junit test class.
This is my code:
#Configuration
#PropertySource("cassandra.properties")
#EnableCassandraRepositories(basePackages = "...repository")
public class Beandef
{
#Autowired
public Environment environment;
CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean();
#Bean(name = "clusterFactory")
public CassandraClusterFactoryBean getCluster() {
PoolingOptions poolingOptions = new PoolingOptions();
cluster.setContactPoints(environment.getProperty("cassandra.contactpoints"));
cluster.setPoolingOptions(poolingOptions);
cluster.setPort(Integer.parseInt(environment.getProperty("cassandra.port")));
poolingOptions.setNewConnectionThreshold(HostDistance.LOCAL, 50);
return cluster;
}
#Bean
#DependsOn("clusterFactory")
public CassandraSessionFactoryBean getSession() throws Exception {
CassandraSessionFactoryBean session = new CassandraSessionFactoryBean();
session.setCluster(cluster.getObject());
session.setKeyspaceName(environment.getProperty("cassandra.keyspace"));
session.setConverter(new MappingCassandraConverter(new CassandraMappingContextAware()));
session.setSchemaAction(SchemaAction.NONE);
return session;
}
If you're using Spring Boot, and if your test class doesn't have a #SpringBootApplication available in the classpath, you have to add #EnableAutoConfiguration to enable Spring Boot auto-config (even with spring-boot-starter-data-cassandra in your dependencies).

Spring Boot 1.2.5.RELEASE & Spring Security 4.0.2.RELEASE - How to load configuration file before security context initialization?

I'm facing a problem with Spring: I'm migrating from Spring Security ver. 3.2.7.RELEASE to 4.0.2.RELEASE. Everything was working fine in older version, however a problem occured when it came to loading DataSource.
Let me describe the architecture:
Application is secured with both SAML and LDAP mechanisms (SAML configuration is pretty similar to config given here: https://github.com/vdenotaris/spring-boot-security-saml-sample/blob/master/src/main/java/com/vdenotaris/spring/boot/security/saml/web/config/WebSecurityConfig.java).
They both need to connect to database in order to get some required data. We use MyBatis with Spring Mybatis to get needed data. That's, where the problem begins.
My DAO configuration class looks like this:
#Configuration
#EnableConfigurationProperties
#MapperScan(basePackages = { "pl.myapp" })
public class DaoConfiguration {
#Bean
#Primary
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Bean
#Primary
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource());
}
#Bean
#Primary
public SqlSessionFactoryBean sqlSessionFactoryBean() {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource());
// some stuff happens here
return sqlSessionFactoryBean;
}
#Bean
#Primary
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
#Bean
#ConfigurationProperties(prefix = "liquibase.datasource")
#ConditionalOnProperty(name="liquibase.enabled")
public DataSource liquibaseDataSource() {
DataSource liquiDataSource = DataSourceBuilder.create().build();
return liquiDataSource;
}
}
In previous version it worked like a charm, but now it has a problem loading mappers, resulting in Bean creation exception on FactoryBean type check: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'someMapper' defined in file [<filename>]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required
over and over again (it's not my problem, it's a known Spring/MyBatis bug).
I did some debugging and discovered something interesting: it looks like DaoConfiguration is not treated like a configuration here! I mean: if I add
#Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
return sqlSessionFactoryBean().getObject();
}
to this config, "normal" call of #Bean annotated method should result in calling proper interceptor, here it lacks this funcionality.
My prediction is that: this config class has not been properly wrapped yet and Spring Security already needs beans produced by it.
Is there any solution to properly load this configuration before Spring Security is initialized? Or am I just wrong and missing something (maybe not so) obvious?

Spring Mongodb: How to configurer mongoDB with MongoClientFactoryBean

When configuring MongoDB in Spring, the reference sais:
register MongoDB like this:
#Configuration
public class AppConfig {
/*
* Use the standard Mongo driver API to create a com.mongodb.Mongo instance.
*/
public #Bean Mongo mongo() throws UnknownHostException {
return new Mongo("localhost");
}
}
pollutes the code with the UnknownHostException checked exception. The use of the checked exception is not desirable as Java based bean metadata uses methods as a means to set object dependencies, making the calling code cluttered.
so Spring proposes
#Configuration
public class AppConfig {
/*
* Factory bean that creates the com.mongodb.Mongo instance
*/
public #Bean MongoFactoryBean mongo() {
MongoFactoryBean mongo = new MongoFactoryBean();
mongo.setHost("localhost");
return mongo;
}
}
But unfortunately since Spring-Data-MongoDB 1.7 MongoFactoryBean has been deprecated and replaced by MongoClientFactoryBean.
So
#Bean
public MongoClientFactoryBean mongoClientFactoryBean() {
MongoClientFactoryBean factoryBean = new MongoClientFactoryBean();
factoryBean.setHost("localhost");
return factoryBean;
}
Then it's time to configure MongoDbFactory which has only one implementation SimpleMongoDbFactory. The SimpleMongoDbFactory has only two initializer not deprecated one of which is SimpleMongoDbFactory(MongoClient, DataBase).
But MongoClientFactoryBean can only return type of Mongo instead of MongoClient.
So, am I missing something to make this pure Spring configuration work?
Yes it returns a Mongo :-(
But as MongoClient extends Mongo that'll be ok anyway, just #Autowire the bean as a Mongo
#Autowired
private Mongo mongo;
Then use it
MongoOperations mongoOps = new MongoTemplate(mongo, "databaseName");
Do you really need the SimpleMongoDbFactory ? See this post.
In my case, I'm using the following code to create MongoTemplate. I'm using MongoRespository. As it only needs MongoTemplate I need to create the MongoTemplate bean only.
#Bean
public MongoTemplate mongoTemplate() throws Exception {
MongoClient mongoClient = new MongoClient("localhost");
MongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(mongoClient, "kyc_reader_test");
return new MongoTemplate(mongoDbFactory);
}
In my configuration file, I've added
#EnableMongoRepositories(basePackages = "mongo.repository.package.name")

Resources