SpringMVC's ApplicationContext access causes NullPointerException - java

Whenever I try to get SpringMVC's ApplicationContext, a NullPointerException is thrown.
This is my userDao:
package com.markor.smarthome.dao;
import com.markor.smarthome.entities.Users;
import com.markor.smarthome.utilites.SpringContextUtil;
import com.markor.smarthome.utilites.StringUtilty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.HashMap;
import java.util.Map;
/**
* Created by litongjie on 2015/5/12.
*/
public class UserDao {
private JdbcTemplate jdbcTemplate = (JdbcTemplate) SpringContextUtil.getBeans("jdbcTemplate");
private String isExistSql = "SELECT * FROM users WHERE user_id=?";
private String addUserSql = "INSERT INTO users(`user_id`,`password`,`name`,`email`,`note`)VALUES(?,?,?,?,?)";
public boolean isExist(String userID) {
Users user = jdbcTemplate.queryForObject(isExistSql, Users.class, userID);
//如果为空 返回false不存在
if (StringUtilty.isNullOrEmpty(user.getUser_id())) {
return false;
} else return true;
}
public int AddUser(Users user) {
System.out.println("begen");
Map<String, Object> map = new HashMap<>();
map.put("user_id", user.getUser_id());
map.put("password", user.getPassword());
map.put("name", user.getName());
map.put("email", user.getEmail());
map.put("note", user.getNote());
int i = jdbcTemplate.update(addUserSql, map);
return i;
}
public static void main(String[] args) {
System.out.println("main begin");
Users users = new Users();
users.setUser_id("123");
users.setName("LI");
users.setNote("444");
System.out.println("user end"+users);
UserDao userDao = new UserDao();
System.out.print(userDao.AddUser(users));
}
}
This is my SpringContextUtil
package com.markor.smarthome.utilites;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.servlet.ServletContext;
/**
* 获取Spring上下文及国际化
*
* #author bingchuan -->www.vijun.com
*/
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext application = null;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.application = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return application;
}
public static Object getBeans(String beanname) {
ApplicationContext applicationContext = getApplicationContext();
return applicationContext.getBean(beanname);
}
I tried using some other's answers, but it didn't work either. Here is my exception:
Exception in thread "main" java.lang.NullPointerException
at com.markor.smarthome.utilites.SpringContextUtil.getBeans(SpringContextUtil.java: 31)
at com.markor.smarthome.dao.UserDao.(UserDao.java:18)
at com.markor.smarthome.dao.UserDao.main(UserDao.java:50)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

That looks completely wrong. Where did you start up your spring context?
If you want to use it somewhere in the main() method, you have to write something like this:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/application-context.xml");
(but in that case you don't need SpringContextUtil, because you already have your context).
But why don't you add UserDao to the context and let spring inject jdbcTemplate bean into it?
something like this:
UserDao:
public class UserDao {
#Autowire
private JdbcTemplate jdbcTemplate;
.....
spring context:
<bean id="jdbcTemplate" class=.../>
<bean id="userDao" class="com.markor.smarthome.dao.UserDao"/>

Related

not able to autowire yml config class from spring boot application [duplicate]

This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 5 years ago.
I am not able to #autowire a class in spring boot application. below is the project explorer snapshot:
From my main class CrmDisconnectionApplication, I am calling DisconnectionConTrigger class. In that class I am doing #autowire for YamlConfig. But I am getting null pointer exception.
below is the code:
CrmDisconnectionApplication
package com.wpits.crm.disconnection;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.wpits.crm.disconnection.quartzJob.DisconnectionCronTrigger;
#SpringBootApplication(scanBasePackages = { "com.wpits.crm" })
public class CrmDisconnectionApplication {
public static void main(String[] args) {
SpringApplication.run(CrmDisconnectionApplication.class, args);
DisconnectionCronTrigger disconnectionCronTrigger = DisconnectionCronTrigger.getInstance();
disconnectionCronTrigger.initialize();
}
}
DisconnectionCronTrigger
package com.wpits.crm.disconnection.quartzJob;
import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.wpits.crm.disconnection.config.YamlConfig;
#Component
public class DisconnectionCronTrigger {
#Autowired
private YamlConfig myConfig;
private static DisconnectionCronTrigger obj = null;
private DisconnectionCronTrigger() {}
public static DisconnectionCronTrigger getInstance() {
if(obj == null) {
obj = new DisconnectionCronTrigger();
}
return obj;
}
public void initialize() {
System.out.println("using environment: " + myConfig.getEnvironment());
System.out.println("name: " + myConfig.getName());
System.out.println("servers: " + myConfig.getServers());
System.out.println("hobies: "+myConfig.getHobies());
JobDetail job = JobBuilder.newJob(DisconnectionJob.class).withIdentity("DisconnectionJob", "group1").build();
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("cronTrigger", "group1").withSchedule(CronScheduleBuilder.cronSchedule("0/10 * * * * ?")).build();
try {
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
}catch(Exception ex) {
ex.printStackTrace();
}
}
}
YamlConfig
package com.wpits.crm.disconnection.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import java.util.*;
#Configuration
#EnableConfigurationProperties
#ConfigurationProperties
public class YamlConfig {
private String name;
private String environment;
private List<String> servers = new ArrayList<>();
private List<String> hobies = new ArrayList<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEnvironment() {
return environment;
}
public void setEnvironment(String environment) {
this.environment = environment;
}
public List<String> getServers() {
return servers;
}
public void setServers(List<String> servers) {
this.servers = servers;
}
public List<String> getHobies() {
return hobies;
}
public void setHobies(List<String> hobies) {
this.hobies = hobies;
}
}
I am getting null pointer exception for line System.out.println("using environment: " + myConfig.getEnvironment()); in class DisconnectionCronTrigger. Where am I getting it wrong. Please correct me..
The problem is this line
DisconnectionCronTrigger disconnectionCronTrigger = DisconnectionCronTrigger.getInstance();
In getInstance you are creating a new object using new. You should not do new, instead Autowire the bean or get it from Spring application context.
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(CrmDisconnectionApplication.class, args);
DisconnectionCronTrigger disconnectionCronTrigger = (DisconnectionCronTrigger)context.getBean("disconnectionCronTrigger");
disconnectionCronTrigger.initialize();
}
If you do it like this, then you will get an object will all the fields in the bean autowired. If you create a object using new, then you wont.

Query is always execute before than AOP in SpringBoot and MyBatis application for dynamic datasource

Here , I want to make a SpringBoot and MyBatis application use dynamic datasource by AOP; But the AOP is always execute after query from database, so switch datasource is invalid because select is finished.
All my code is in https://github.com/helloworlde/SpringBoot-DynamicDataSource/tree/aspect_dao
My dependence is
compile('org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.1')
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.boot:spring-boot-starter-aop')
runtime('mysql:mysql-connector-java')
And application.properties
application.server.db.master.driver-class-name=com.mysql.jdbc.Driver
application.server.db.master.url=jdbc:mysql://localhost/redisapi?useSSL=false
application.server.db.master.port=3306
application.server.db.master.username=root
application.server.db.master.password=ihaveapen*^##
#application.server.db.master.database=123456
#
## application common config
application.server.db.slave.driver-class-name=com.mysql.jdbc.Driver
application.server.db.slave.url=jdbc:mysql:/localhost/redisapi2?useSSL=false
application.server.db.slave.port=3306
application.server.db.slave.username=root
application.server.db.slave.password=123456
#application.server.db.slave.database=redisapi
mybatis.type-aliases-package=cn.com.hellowood.dynamicdatasource.mapper
mybatis.mapper-locations=mappers/**Mapper.xml
Table
CREATE TABLE product(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
price DOUBLE(10,2) NOT NULL DEFAULT 0
);
DataSourceConfigur.java
package cn.com.hellowood.dynamicdatasource.configuration;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
#Configuration
public class DataSourceConfigurer {
#Bean("master")
#Primary
#ConfigurationProperties(prefix = "application.server.db.master")
public DataSource master() {
return DataSourceBuilder.create().build();
}
#Bean("slave")
#ConfigurationProperties(prefix = "application.server.db.slave")
public DataSource slave() {
return DataSourceBuilder.create().build();
}
#Bean("dynamicDataSource")
public DataSource dynamicDataSource() {
DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource();
Map<Object, Object> dataSourceMap = new HashMap<>(2);
dataSourceMap.put("master", master());
dataSourceMap.put("slave", slave());
// Set master datasource as default
dynamicRoutingDataSource.setDefaultTargetDataSource(master());
// Set master and slave datasource as target datasource
dynamicRoutingDataSource.setTargetDataSources(dataSourceMap);
// To put datasource keys into DataSourceContextHolder to judge if the datasource is exist
DynamicDataSourceContextHolder.dataSourceKeys.addAll(dataSourceMap.keySet());
return dynamicRoutingDataSource;
}
#Bean
#ConfigurationProperties(prefix = "mybatis")
public SqlSessionFactoryBean sqlSessionFactoryBean() {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
// Here is very important, if don't config this, will can't switch datasource
// put all datasource into SqlSessionFactoryBean, then will autoconfig SqlSessionFactory
sqlSessionFactoryBean.setDataSource(dynamicDataSource());
return sqlSessionFactoryBean;
}
#Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dynamicDataSource());
}
}
DynamicRoutingDataSource.java
package cn.com.hellowood.dynamicdatasource.configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
private final Logger logger = LoggerFactory.getLogger(getClass());
#Override
protected Object determineCurrentLookupKey() {
logger.info("Current DataSource is [{}]", DynamicDataSourceContextHolder.getDataSourceKey());
return DynamicDataSourceContextHolder.getDataSourceKey();
}
}
DynamicDataSourceContextHolder.java
package cn.com.hellowood.dynamicdatasource.configuration;
import java.util.ArrayList;
import java.util.List;
public class DynamicDataSourceContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>() {
#Override
protected String initialValue() {
return "master";
}
};
public static List<Object> dataSourceKeys = new ArrayList<>();
public static void setDataSourceKey(String key) {
contextHolder.set(key);
}
public static String getDataSourceKey() {
return contextHolder.get();
}
public static void clearDataSourceKey() {
contextHolder.remove();
}
public static boolean containDataSourceKey(String key) {
return dataSourceKeys.contains(key);
}
}
DynamicDataSourceAspect.java
package cn.com.hellowood.dynamicdatasource.configuration;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
#Aspect
#Order(-100) // To ensure execute before #Transactional
#Component
public class DynamicDataSourceAspect {
private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);
private final String QUERY_PREFIX = "select";
#Pointcut("execution( * cn.com.hellowood.dynamicdatasource.mapper.*.*(..))")
public void daoAspect() {
}
#Before("daoAspect()")
public void switchDataSource(JoinPoint point) {
if (point.getSignature().getName().startsWith(QUERY_PREFIX)) {
DynamicDataSourceContextHolder.setDataSourceKey("slave");
logger.info("Switch DataSource to [{}] in Method [{}]",
DynamicDataSourceContextHolder.getDataSourceKey(), point.getSignature());
}
}
#After("daoAspect())")
public void restoreDataSource(JoinPoint point) {
DynamicDataSourceContextHolder.clearDataSourceKey();
logger.info("Restore DataSource to [{}] in Method [{}]",
DynamicDataSourceContextHolder.getDataSourceKey(), point.getSignature());
}
}
And have Controller, Service and Dao for query, But although I set Order of aspect as -100, it still execute query before AOP, could anyone find where is wrong, Thank you very much.
This is log screenshot
Finally I fixed this issue, Because I injected Bean of DataSourceTransactionManager, So transaction will be open in Service, so the aspect of DAO is not work until transaction finished.
Delete this code:
#Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dynamicDataSource());
}

Spring - Reading Properties (java.lang.IllegalArgumentException: Could not resolve placeholder 'name' in string value "${name}")

I see the below the error when I tried to read properties from classpath in my Spring project using #PropertySource annotation. I have pasted my code below , please can you help in letting me know what I am missing? Thanks.
WARNING: Exception encountered during context initialization -
cancelling refresh attempt:
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'customerRepository': Injection of autowired
dependencies failed; nested exception is
java.lang.IllegalArgumentException: Could not resolve placeholder
'name' in string value "${name}"
Exception in thread "main"
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'customerRepository': Injection of autowired
dependencies failed; nested exception is
java.lang.IllegalArgumentException: Could not resolve placeholder
'name' in string value "${name}"
AppConfig.java
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.Scope;
import com.vivek.service.CustomerService;
import com.vivek.service.CustomerServiceImpl;
#Configuration
#ComponentScan("com.vivek")
#PropertySource("app.properties")
public class AppConfig {
#Bean
public static PropertyPlaceholderConfigurer getPropertyPlaceholderConfigurer(){
PropertyPlaceholderConfigurer p = new PropertyPlaceholderConfigurer();
//p.setIgnoreUnresolvablePlaceholders(true);
return p;
}
#Bean(name="customerService")
#Scope("prototype")
public CustomerService getCustomerService(){
CustomerServiceImpl service = new CustomerServiceImpl();
//service.setRepository(getCustomerRepository());
return service;
}
/* #Bean(name="customerRepository")
public CustomerRepository getCustomerRepository(){
CustomerRepository repository = new HibernateCustomerRepository();
return repository;
}*/
}
Application.java
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.vivek.service.CustomerService;
import com.vivek.service.CustomerServiceImpl;
public class Application {
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
CustomerService service = context.getBean("customerService",CustomerService.class);
System.out.println(service);
CustomerService service1 = context.getBean("customerService",CustomerService.class);
System.out.println(service1);
System.out.println(service.findAll().get(0).getFirstName());
System.out.println(service.findAll().get(0).getLastName());
}
}
HibernateCustomerRepository.java
package com.vivek.repository;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;
import com.vivek.model.Customer;
#Repository("customerRepository")
public class HibernateCustomerRepository implements CustomerRepository {
/* (non-Javadoc)
* #see com.vivek.repository.CustomerRepository#findAll()
*/
#Value("${name}")
private String name;
#Override
public List<Customer> findAll(){
List<Customer> customerList = new ArrayList<Customer>();
Customer customer = new Customer();
customer.setFirstName(name);
customer.setLastName("Shah");
customerList.add(customer);
return customerList;
}
}
CustomerServiceImpl.java
package com.vivek.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import com.vivek.model.Customer;
import com.vivek.repository.CustomerRepository;
import com.vivek.repository.HibernateCustomerRepository;
public class CustomerServiceImpl implements CustomerService {
/* (non-Javadoc)
* #see com.vivek.service.CustomerService#findAll()
*
*/
private CustomerRepository repository;
#Autowired
public void setRepository(CustomerRepository repository) {
this.repository = repository;
}
#Override
public List<Customer> findAll(){
CustomerRepository repository = new HibernateCustomerRepository();
return repository.findAll();
}
}
app.properties
name=Arnold
May be you need to declare PropertySourcesPlaceholderConfigurer in spring config file.
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>config.properties</value>
</property>
</bean>

ResourceResolverFactory is NULL (Adobe Experience Manager AEM)

I am trying to get a reference to the ResourceResolver from the ResourceResolverFactory as follows:
#Reference
private ResourceResolverFactory resourceResolverFactory;
public void someMethod() {
Map<String, Object> authenticationMap = new HashMap<String, Object>();
authenticationMap.put(ResourceResolverFactory.USER, "user");
authenticationMap.put(ResourceResolverFactory.PASSWORD, "pwd");
//This line returns NullPointerException
ResourceResolver resourceResolver = resourceResolverFactory.getResourceResolver(authenticationMap);
}
Can someone please tell me what I am doing wrong? The AEM API version v6.0.
So what I did was to create an Activator class that is called when the bundle is deployed and started. The Activator class then gets the instance of org.apache.sling.jcr.api.SlingRepository which we can use to connect to the JCR. Here is the activator code:
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.jcr.api.SlingRepository;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#Component(immediate = true, label = "Commons Activator")
public class Activator implements BundleActivator {
#Reference
private SlingRepository repository;
private static final Logger logger = LoggerFactory.getLogger(Activator.class);
#Activate
#Override
public void start(BundleContext context) throws Exception {
logger.info(context.getBundle().getSymbolicName() + " started");
//My own factory class instance
ResourceResolverDiscoveryService rrf = ResourceResolverDiscoveryService.getInstance();
//Set the 'repository' in your factory class instance
rrf.setSlingRepositoryFactory(repository);
}
#Deactivate
#Override
public void stop(BundleContext context) throws Exception {
logger.info(context.getBundle().getSymbolicName() + " stopped");
}
}
Then in the class where I want to use JCR to store the data I did the following:
public class StoreInJCR {
public void store(Quote quote) throws LoginException, RepositoryException {
SlingRepository slingRepository = ResourceResolverDiscoveryService.getInstance().getSlingRepositoryFactory();
// GOT IT!!! Mission Accomplished
Session session = slingRepository.loginAdministrative(null);
Node root = session.getRootNode();
// Further code
.
.
}
}
Hope someone finds this useful.

How to create dynamic proxy with Spring and Java

I have this situation:
I have one interface Service which aggregates all service interfaces. So for example if I have two interfaces ILoginService1 and ILoginService2 the Service interface looks like this
Service extends ILoginService1,ILoginService2.
I need this interface to be accessible in a given context like this:
service.login();
This is my solution (something similar to http://artofsoftwarereuse.com/tag/dynamic-proxy/):
I create one annotation ServiceFacade, which I put on Service interface, then I have BeanPostProcessor in which I create DynamicProxy for the Service interface.
But the problem is that Service interface isn't pick up from spring component scan, even in the case I put #Component on it, but other components are put in Spring container.
How can I fix my solution so far or I'm missing something or is there other solutions?
Here is source code:
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
<context:component-scan base-package="org.finki.auction.ui.application"/>
<context:component-scan base-package="org.finki.auction.services"/>
</beans>
Annotation:
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface ServiceFacade{}
Invocation Handler for Dynamic Proxy:
/**
*
*/
package org.finki.auction.services;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
/**
*
*/
#Component("serviceLayer")
public class ServiceLayer implements InvocationHandler, ApplicationContextAware
{
private static ApplicationContext applicationContext = null;
private static Map<String, String> serviceMap = new HashMap<>();
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
Object result;
try
{
String searchKey = method.getName();
String beanName = serviceMap.get(searchKey);
Object methodObject = applicationContext.getBean(beanName);
result = method.invoke(methodObject, args);
} catch (InvocationTargetException e)
{
throw e.getTargetException();
} catch (Exception e)
{
throw new RuntimeException("unexpected invocation exception: " + e.getMessage());
}
return result;
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
ServiceLayer.applicationContext = applicationContext;
Map<String, Object> beans = applicationContext.getBeansWithAnnotation(Service.class);
for (Map.Entry<String, Object> entryBean : beans.entrySet())
{
String beanName = entryBean.getKey();
Object beanObject = entryBean.getValue();
Method[] beanMethods = beanObject.getClass().getDeclaredMethods();
for (Method bMethod : beanMethods)
{
serviceMap.put(bMethod.getName(), beanName);
}
}
}
}
BeanPostProcessor class:
/**
*
*/
package org.finki.auction.services.annotation;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import org.finki.auction.services.Service;
import org.finki.auction.services.ServiceLayer;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
*
*/
#Component("serviceFacadeProcessor")
public class ServiceFacadeProcessor implements BeanPostProcessor, ApplicationContextAware
{
private static ApplicationContext applicationContext = null;
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
{
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
{
Class<?> clz = bean.getClass();
Class<?>[] tmpInterfaces = clz.getInterfaces();
System.out.println("ServiceFacadeProcessor : " + bean);
if (tmpInterfaces != null && tmpInterfaces.length == 1
&& tmpInterfaces[0].isAnnotationPresent(ServiceFacade.class))
{
System.out.println("Find serviceFacade >>>>");
Class<?>[] interfaces = Arrays.copyOf(tmpInterfaces, tmpInterfaces.length + 1);
interfaces[tmpInterfaces.length] = Service.class;
ClassLoader cl = bean.getClass().getClassLoader();
ServiceLayer serviceLayerBean = applicationContext.getBean("serviceLayer", ServiceLayer.class);
Object t = Proxy.newProxyInstance(cl, interfaces, serviceLayerBean);
System.out.println("Find serviceFacade <<<<");
return t;
}
return bean;
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
ServiceFacadeProcessor.applicationContext = applicationContext;
}
}
So, my problem is not the configuration, my problem is how to attach Service interface to spring container in order to be caught by BeanPostProcessor and create dynamic proxy for it. It's is my solution so far maybe I'm missing something, but if someone have better way doing it, just let me now.
Thanks in advance
Solution:
/**
*
*/
package org.finki.auction.services.annotation;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import org.finki.auction.services.Service;
import org.finki.auction.services.ServiceLayer;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* #author
*
*/
#Component
public class ServiceFactoryBean implements FactoryBean<Service>, ApplicationContextAware
{
private static ApplicationContext applicationContext = null;
#Override
public Service getObject() throws Exception
{
Class<?>[] tmpInterfaces = Service.class.getInterfaces();
Class<?>[] interfaces = Arrays.copyOf(tmpInterfaces, tmpInterfaces.length + 1);
interfaces[tmpInterfaces.length] = Service.class;
ServiceLayer serviceLayerBean = applicationContext.getBean("serviceLayer", ServiceLayer.class);
ClassLoader cl = serviceLayerBean.getClass().getClassLoader();
Object t = Proxy.newProxyInstance(cl, interfaces, serviceLayerBean);
return (Service) t;
}
#Override
public Class<?> getObjectType()
{
return Service.class;
}
#Override
public boolean isSingleton()
{
return true;
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
ServiceFactoryBean.applicationContext = applicationContext;
}
}
Also need to delete BeanPostProcessor and annotation.
I run into something similar and believe you can get your scenario working using Spring's Java Configuration feature.
#Configuration
public class ServiceConfiguration {
// you can wire your service1 and service2 here
#Bean
Service service() {
// create and return dynamic proxy here
}
}
This way you will end up with a bean of type 'Service' and name 'service' which will be your dynamic proxy with invocation handler etc.
I'm sure Java Configuration will not limit you to the approach outlined above (where you wire your service1 and service2 into the config) - methinks that is implementation detail.

Categories

Resources