I'm working on a semi-large application using Spring 3 and am running into performance problems when throwing hundreds of users at it at once. I'm using several request scoped beans using Spring's AOP proxy and I can see that every time I call any method on one of these beans, the CGLIB interceptor is invoked, which then calls AbstractBeanFactory.getBean(), which calls add() on a Synchronized Set of existing Spring beans. Since this add() is synchronized, it effectively locks up the server when there are thousands of calls to it all waiting to add to the same list.
Is there a way to get around this using request scoped beans? I read in the Spring documentation that CGLIB isn't used if the bean implements any interface (http://static.springsource.org/spring/docs/2.0.0/reference/aop.html#d0e9015) but my request scoped beans all implement one (the same one in fact) and it's still happening. And I definitely need the beans to be request scoped because some of their fields are calculated in one part of the app for a particular request and then I use SpEL to get their value in a different part of the app during the same request. I think if I made the beans prototype scoped, I'd have a fresh object when I used SpEL to get them the second time.
Here is a code sample that illustrates my problem. See the last two lines for comments describing where exactly I'm having issues.
<!-- Spring config -->
<bean name="someBean" class="some.custom.class.SomeClass" scope="request">
<property name="property1" value="value1"/>
<property name="property2" value="value2"/>
<aop:scoped-proxy/>
</bean>
<bean name="executingClass" class="some.other.custom.class.ExecutingClass" scope="singleton">
<property name="myBean" ref="someBean" />
</bean>
public Interface SomeInterface {
public String getProperty1();
public void setProperty1(String property);
public String getProperty2();
public void setProperty2(String property);
}
public class SomeClass implements SomeInterface {
private String property1;
private String property2;
public String getProperty1() { return propery1; }
public void setProperty1(String property) { property1=property;}
public String getProperty2() { return propery2; }
public void setProperty2(String property) { property2=property;}
}
public class ExecutingClass {
private SomeInterface myBean;
public void execute() {
String property = myBean.getProperty1(); // CGLIB interceptor is invoked here, registering myBean as a bean
String otherProperty = myBean.getProperty2(); // CGLIB interceptor is invoked here too! Seems like this is unnecessary. And it's killing my app.
}
}
My ideas are one of the following:
Can I make a Spring Bean request scoped without proxying every method call made on the bean? And without marking every method as "final"?
or...
Can I override Spring's bean factory to implement a Bean cache that will check if a bean is cached before calling AbstractBeanFactory.getBean()? And if so, where do I configure Spring to use my custom bean factory?
As it turns out, Spring actually does cache the request scoped beans, in the request attributes. If you're curious, take a look at AbstractRequestAttributesScope, which RequestScope extends:
public Object get(String name, ObjectFactory objectFactory) {
RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
Object scopedObject = attributes.getAttribute(name, getScope());
if (scopedObject == null) {
scopedObject = objectFactory.getObject();
attributes.setAttribute(name, scopedObject, getScope());
}
return scopedObject;
}
So while AbstractBeanFactory.getBean() does get called on every bean method call because of the aop proxy, it only causes Spring to add to that synchronized set if the bean wasn't already found in the request attributes.
Avoiding the proxying of every method call on my request scoped beans would still reduce complexity but with this caching in place, the performance impact would be minimal. I think the slow performance is something I'm going to have to live with if I want a ton of request scoped beans and still serve a ton of requests at a time.
Interesting question.
It turns out that Spring's scoped proxy doesn't cache resolved objects, so that every access to the scoped proxy causes getBean() to be called.
As a workaround, you can create a poor man's caching scoped proxy, something like this (untested, target bean should be request-scoped, but without <aop:scoped-proxy />):
public class MyScopedProxy implements SomeInterface, BeanFactoryAware {
private BeanFactory factory;
private Scope scope;
private String targetBeanName;
private ThreadLocal<SomeInterface> cache = new ThreadLocal<SomeInterface>();
private SomeInterface resolve() {
SomeInterface v = cache.get();
if (v == null) {
v = (SomeInterface) factory.getBean(targetBeanName);
cache.set(v);
scope.registerDestructionCallback(targetBeanName, new Runnable() {
public void run() {
cache.remove();
}
});
}
return v;
}
public void setBeanFactory(BeanFactory factory) {
this.factory = factory;
this.scope = ((ConfigurableBeanFactory) factory).getRegisteredScope("request");
}
public String getProperty() {
return resolve().getProperty();
}
...
}
Regarding the proxying mechanisms: unlike other AOP proxies, scoped proxies are CGLIB by default, you can override it by setting <aop:scoped-proxy proxy-target-class = "false" />, but it wouldn't help in this case.
One option is to replace injecting a scoped proxy with a lookup-method:
public abstract class ExecutingClass {
protected abstract SomeInterface makeMyBean();
public void execute() {
SomeInterface myBean = makeMyBean();
String property = myBean.getProperty1();
String otherProperty = myBean.getProperty2();
}
}
That will ensure Spring is asked for the bean only once per request, eliminate any overhead due to the scoped proxy, and shorten stack traces. It is less flexible (in that you can not arbitrarily share references to the request scoped bean and have the scoped proxy use the right bean) but you might not need the flexibility.
Related
I have a class that is instantiated by 3rd party code (it uses reflection to create the object.) I provide the implementation of their interface and they create the object. In my implementation I want to use CDI to inject a service that performs logic. What is the correct way to do this?
public interface ThirdPartyInterface {
public void DoSomething();
}
public class InjectedService {
public void DoSomeLogic() { ... }
}
public class MyImplementation implements ThirdPartyInterface {
#Inject InjectedService service;
#Override
public void DoSomething() {
service.DoSomeLogic();
}
}
I originally thought this would work through the magic of CDI, but found my service object to be null.
The only thing I've come up with so far is to inject the service manually in the constructor
public MyImplementation() {
CDI<Object> cdi = CDI.current();
service = cdi.select(InjectedService.class).get();
}
Is this the correct/only/best way of obtaining the instance? I am using Weld for my CDI implementation.
I have also found this to work in the constructor:
public MyImplementation() {
CDI<Object> cdi = CDI.current();
BeanManager bm = cdi.getBeanManager();
AnnotatedType<MyImplementation> myType = bm.createAnnotatedType(MyImplementation.class);
Set<Bean<?>> beans = bm.getBeans(MyImplementation.class);
Bean<?> bean = bm.resolve(beans);
#SuppressWarnings("unchecked")
CreationalContext<MyImplementation> cc = (CreationalContext<MyImplementation>)bm.createCreationalContext(bean);
bm.createInjectionTarget(myType).inject(this, cc);
}
So long as someone creates the object manually, CDI will not, by default, inject anything into it.
You approach with the constructor injection is probably going to work, unless you get into EARs and such where CDI.current() may not do what you would expect.
There is a way to make CDI inject into manually created objects - the 3rd party would have to take this step to make it work. You need BeanManager and an instance you want to inject into:
BeanManager beanManager = ...; // get hold of bean manager, can be injected
CreationalContext<Object> ctx = beanManager.createCreationalContext(null);
#SuppressWarnings("unchecked")
InjectionTarget<MyImplementation> injectionTarget = (InjectionTarget<MyImplementation>) beanManager
.getInjectionTargetFactory(beanManager.createAnnotatedType(myImplementationInstance.getClass())).createInjectionTarget(null);
injectionTarget.inject(myImplementationInstance, ctx);
Note - by doing this you take responsibility to clean up after the object once you no longer need it. Store the CreationContext somewhere and call release() method on it in order to dispose of it properly (with all possible pre destroy calls and such).
Alternatively, since you are already using CDI, why doesn't 3rd party simply #Inject the bean you provide?
I have a web application with JAX-RS, CDI and EJB. In each resource I inject a Stateless SessionBean, and my question is whether it is possible to inject the same instances into a provider of JAX-RS and the Stateless SesionBean. I am trying to pass some data that come in each request to the Stateless SesionBean from a ContainerRequestFilter. All EJB components are accessed only by jax rs resources.
Example:
public class Bean {
private String attr;
// getter and setter
}
#Stateless
public class BeanService {
#Inject
Bean bean;
public void doStuff() {
bean.getAttr();
// do something with bean.attr
}
}
#Path("/bean")
public class BeanResource {
#Inject
BeanService service;
#GET
public void doStuff() {
service.doStuff():
}
}
#Provider
public class BeanRequestFilter implements ContainerRequestFilter {
#Inject
Bean bean;
#Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
String data = null; // <- get data from request
bean.setAttr(data);
}
}
Update
Change the Bean for Pojo, my only intention is use a class that hold some state that come in every request and can be transmited in each invocation, since the PojoResource to PojoService. I want to do it in this way because all the services retrive this data and I don't want to pass this as parameter on every method.
This looks like your Bean class is essentially request scoped, so changing it to:
#RequestScoped
public class Bean {
...
}
should have the desired effect. The same instance will be injected in both the BeanRequestFilter and the BeanService.
However, I think you may also get what you're looking for by injecting the ContainerRequestContext directly into the BeanService and forgetting about Bean altogether.
#Stateless
public class BeanService {
#Context
ContainerRequestContext containerRequestContext;
public void doStuff() {
// <- get data from request
}
}
If you want the Bean to be a kind of singleton using CDI see the #ApplicationScoped annotation (in that case Bean should be Sersializable)
Or if you want the EJB BeanService to be a singleton see the #Singleton annotation
Before answering the question, Bean should never be updated. A concept of bean is that which provides a service, and uses data to process a request.
That said, you can of course provide data as bean, but then the data needs to be produced at one point to be used, and not to be updated.
I would therefore use the BeanRequestFilter to produce the bean, and let the BeanService inject the produced bean.
This notwithstanding however, i see that this is a request based data? is it a header data?, request parameter? Then i would suggest that you use the jax-rs #QueryParam or #HeaderParam or #PathParam or #FormParam or #CookieParam within the jax-rs resource class, and then provide the data as a domain object parameter to your BeanService thus:
#Path("/api/resource-path")
public class MyResource {
public void processSomething(#QueryParam("qparam") String param, #HeaderParam("hparam") String hParam) {
MyDomain domain = new MyDomain(qParam, hParam);
myService.process(domain);
}
}
I have some beans (of multiple types, CDI, #Stateless and #Singleton beans). Some of their fields shall get injected from database values.
public class MyBean {
#Inject
#DbConfigValue(MyConfig.HOST)
String host;
}
So I added a custom #Qualifier (DbConfigValue) used by a Producer. The producer reads and caches config values from a database and injects them into the beans.
#Singleton
#Lock(LockType.READ)
public class Configuration {
#Produces
#Dependent
#DbConfigValue
public String getDbConfigValue(InjectionPoint point) {
// get key for the config-value from qualifier-annotation of the injected field
String key = point.getAnnotated().getAnnotation(DbConfigValue.class).value();
// i have read+cached database config values in #PostConstruct before
return cachedConfigValues.get(key);
}
}
This works well for initial injection / bean construction. Some web tutorials out there are suggesting this approach.
Now, I think it is reasonable to assume that config values, if stored in DB, might change at runtime. So, whenever an admin changes a database config value, I currently do fire a CDI-event.
Question: is there any way to re-inject values into fields of already-initialized bean-instances? Or is injection always related to instance-creation only?
E.g. I had s.th. similar to this in mind:
public class MyEventListener {
#Inject
BeanManager beanManager;
#Asynchronous
public void onDbConfigValueChangedEvent (#Observes(during = TransactionPhase.AFTER_SUCCESS) DbConfigValueChangedEvent event) {
try {
// could be filtered by custom qualifier:
Set<Bean<?>> beans = beanManager.getBeans(Object.class,new AnnotationLiteral<Any>() {});
for (Bean<?> bean : beans) {
Set<InjectionPoint> points = bean.getInjectionPoints();
// What now? javax.enterprise.inject.spi.Bean is the
// bean-representation only.
// Can I somehow resolve the actual bean-instances here?
// Then update Field via Reflection?
}
}
catch(Exception e){
// ...
}
}
}
I also considered DeltaSpike which has some methods for injection-control. However, I did only find methods to inject into new bean instances, or even with new- or null-CreationalContexts (beans not CDI-managed afterwards)
Please note: I am aware that I can solve this specific use-case by injecting the configuration and explicitly getting the current values on each request like this:
public class MyBean {
#Inject
Configuration config;
public void someMethod(){
String host = config.getConfig(MyConfig.HOST);
// ...
}
}
However, I am wondering about the question in general: is there any support for re-injection? Or if not, do the specs (CDI or Java EE) forbid it?
Depending on how fast/slow your db is, this may be expensive. You could probably leverage some cacheing mechanism in the producer method.
Leverage on Instance injection mechanims, which lazily loads the actual injected bean.
Your Producer (Probably leveraging on some of cache to avoid db calls all the tome)
#Singleton
#Lock(LockType.READ)
public class Configuration {
#Produces
#RequestScoped //May fail if not in a request-context, but for ejb-calls, it is guaranteed to work as CDI has EJB Request Context
#DbConfigValue
public String getDbConfigValue(InjectionPoint point) {
// get key for the config-value from qualifier-annotation of the injected field
String key = point.getAnnotated().getAnnotation(DbConfigValue.class).value();
// i have read+cached database config values in #PostConstruct before
return cachedConfigValues.get(key);
}
}
And the injection points:
#SessionScoped
public class MyBean {
#Inject
#DbConfigValue(MyConfig.HOST)
private Instance<String> host;
public void doSomething() {
String myHost = host.get(); // of course will throw exception if value is failing. It will be resolved with every request.
}
}
I am using Java7 and Spring3. I have below classes.
Request.java
public interface Request {
public void doProcess();
}
RequestImpl.java
#Transactional
public class RequestImpl implements Request{
private String name;
private String age;
//setters and getters
public void doProcess(){
//use name and age and call third party class which will save data into database
}
}
SpringConfig.xml
<bean id="request" class="pkg.RequestImpl.java" />
Now clients will use RequestImpl as below.
RequestImplreq = (RequestImpl)applicationContext.getBean("request");
req.setName("someName");
req.setAge("20");
req.doProcess();
Now my question is do i need to declare above RequestImpl.java scope as prototype or singleton?
Thanks!
IMHO you are not working well: processes and data to process should be separated (Can DTOs be spring managed beans?) so doProcess() should be defined as doProcess(name,age) or shaded behind a factory or something similar.
Probably the best option is to define
public interface Request {
public void doProcess(String name,String age);
}
#Transactional
public class RequestImpl implements Request{
public void doProcess(String name,String age){
// do what you want
}
}
your SpringConfig.xml stay the same and call code will change to:
Request req= applicationContext.getBean(Request.class);
req.doProcess("someName", "20");
Beside all, perform a ApplicationContext.getBean() and cast result to an implementation is (usually) bad pratice because Spring can proxy returned object and cast to implementation will fail with a ClassCastException
#user3269829 : By default the scope would be singleton now it is totally depend upon your requirement, if you want a bean object for every request then you can go for "prototype" and if you want to share single bean object among the multiple request then you can go for "singleton"
It depends on how your third party class is implemented. If you want to ensure a single instance of your class you can use factory-method of spring beans and ensure single instance.
Check "3.3.2.2 Instantiation with a static factory method" part of Spring Documentation
It should look like this in bean definition:
<!-- the factory bean, which contains a method called createInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<!-- the bean to be created via the factory bean -->
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
and singleton creator:
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
private DefaultServiceLocator() {}
public ClientService createClientServiceInstance() {
return clientService;
}
}
Spring cache is not working when calling cached method from another method of the same bean.
Here is an example to explain my problem in clear way.
Configuration:
<cache:annotation-driven cache-manager="myCacheManager" />
<bean id="myCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="myCache" />
</bean>
<!-- Ehcache library setup -->
<bean id="myCache"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:shared="true">
<property name="configLocation" value="classpath:ehcache.xml"></property>
</bean>
<cache name="employeeData" maxElementsInMemory="100"/>
Cached service :
#Named("aService")
public class AService {
#Cacheable("employeeData")
public List<EmployeeData> getEmployeeData(Date date){
..println("Cache is not being used");
...
}
public List<EmployeeEnrichedData> getEmployeeEnrichedData(Date date){
List<EmployeeData> employeeData = getEmployeeData(date);
...
}
}
Result :
aService.getEmployeeData(someDate);
output: Cache is not being used
aService.getEmployeeData(someDate);
output:
aService.getEmployeeEnrichedData(someDate);
output: Cache is not being used
The getEmployeeData method call uses cache employeeData in the second call as expected. But when the getEmployeeData method is called within the AService class (in getEmployeeEnrichedData), Cache is not being used.
Is this how spring cache works or am i missing something ?
I believe this is how it works. From what I remember reading, there is a proxy class generated that intercepts all requests and responds with the cached value, but 'internal' calls within the same class will not get the cached value.
From https://code.google.com/p/ehcache-spring-annotations/wiki/UsingCacheable
Only external method calls coming in through the proxy are
intercepted. This means that self-invocation, in effect, a method
within the target object calling another method of the target object,
will not lead to an actual cache interception at runtime even if the
invoked method is marked with #Cacheable.
Since Spring 4.3 the problem could be solved using self-autowiring over #Resource annotation:
#Component
#CacheConfig(cacheNames = "SphereClientFactoryCache")
public class CacheableSphereClientFactoryImpl implements SphereClientFactory {
/**
* 1. Self-autowired reference to proxified bean of this class.
*/
#Resource
private SphereClientFactory self;
#Override
#Cacheable(sync = true)
public SphereClient createSphereClient(#Nonnull TenantConfig tenantConfig) {
// 2. call cached method using self-bean
return self.createSphereClient(tenantConfig.getSphereClientConfig());
}
#Override
#Cacheable(sync = true)
public SphereClient createSphereClient(#Nonnull SphereClientConfig clientConfig) {
return CtpClientConfigurationUtils.createSphereClient(clientConfig);
}
}
The example below is what I use to hit the proxy from within the same bean, it is similar to #mario-eis' solution, but I find it a bit more readable (maybe it's not:-). Anyway, I like to keep the #Cacheable annotations at the service level:
#Service
#Transactional(readOnly=true)
public class SettingServiceImpl implements SettingService {
#Inject
private SettingRepository settingRepository;
#Inject
private ApplicationContext applicationContext;
#Override
#Cacheable("settingsCache")
public String findValue(String name) {
Setting setting = settingRepository.findOne(name);
if(setting == null){
return null;
}
return setting.getValue();
}
#Override
public Boolean findBoolean(String name) {
String value = getSpringProxy().findValue(name);
if (value == null) {
return null;
}
return Boolean.valueOf(value);
}
/**
* Use proxy to hit cache
*/
private SettingService getSpringProxy() {
return applicationContext.getBean(SettingService.class);
}
...
See also Starting new transaction in Spring bean
Here is what I do for small projects with only marginal usage of method calls within the same class. In-code documentation is strongly advidsed, as it may look strage to colleagues. But its easy to test, simple, quick to achieve and spares me the full blown AspectJ instrumentation. However, for more heavy usage I'd advice the AspectJ solution.
#Service
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
class AService {
private final AService _aService;
#Autowired
public AService(AService aService) {
_aService = aService;
}
#Cacheable("employeeData")
public List<EmployeeData> getEmployeeData(Date date){
..println("Cache is not being used");
...
}
public List<EmployeeEnrichedData> getEmployeeEnrichedData(Date date){
List<EmployeeData> employeeData = _aService.getEmployeeData(date);
...
}
}
If you call a cached method from same bean it will be treated as a private method and annotations will be ignored
Yes, the caching will not happen because of the reasons that were already mentioned in the other posts. However I would solve the problem by putting that method to its own class (service in this case). With that your code will be easier to maintain/test and understand.
#Service // or #Named("aService")
public class AService {
#Autowired //or how you inject your dependencies
private EmployeeService employeeService;
public List<EmployeeData> getEmployeeData(Date date){
employeeService.getEmployeeData(date);
}
public List<EmployeeEnrichedData> getEmployeeEnrichedData(Date date){
List<EmployeeData> employeeData = getEmployeeData(date);
...
}
}
#Service // or #Named("employeeService")
public class EmployeeService {
#Cacheable("employeeData")
public List<EmployeeData> getEmployeeData(Date date){
println("This will be called only once for same date");
...
}
}
In my Case I add variable :
#Autowired
private AService aService;
So I call the getEmployeeData method by using the aService
#Named("aService")
public class AService {
#Cacheable("employeeData")
public List<EmployeeData> getEmployeeData(Date date){
..println("Cache is not being used");
...
}
public List<EmployeeEnrichedData> getEmployeeEnrichedData(Date date){
List<EmployeeData> employeeData = aService.getEmployeeData(date);
...
}
}
It will use the cache in this case.
Better approach should be creating another service like ACachingService and call ACachingService.cachingMethod() instead of self Autowiring ( or any other approach trying to self inject). This way you do not fall into Circular dependency, which may be resulted in warning/error when upgrade to newer Spring ( Spring 2.6.6 in my case ) :
ERROR o.s.boot.SpringApplication - Application run failed
org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'webSecurityConfig':
Requested bean is currently in creation: Is there an unresolvable circular reference?
We looked at all the solutions here and decided to use a separate class for the cached methods because Spring 5 doesn't like circular dependencies.
Use static weaving to create proxy around your bean. In this case even 'internal' methods would work correctly
I use internal inner bean (FactoryInternalCache) with real cache for this purpose:
#Component
public class CacheableClientFactoryImpl implements ClientFactory {
private final FactoryInternalCache factoryInternalCache;
#Autowired
public CacheableClientFactoryImpl(#Nonnull FactoryInternalCache factoryInternalCache) {
this.factoryInternalCache = factoryInternalCache;
}
/**
* Returns cached client instance from cache.
*/
#Override
public Client createClient(#Nonnull AggregatedConfig aggregateConfig) {
return factoryInternalCache.createClient(aggregateConfig.getClientConfig());
}
/**
* Returns cached client instance from cache.
*/
#Override
public Client createClient(#Nonnull ClientConfig clientConfig) {
return factoryInternalCache.createClient(clientConfig);
}
/**
* Spring caching feature works over AOP proxies, thus internal calls to cached methods don't work. That's why
* this internal bean is created: it "proxifies" overloaded {#code #createClient(...)} methods
* to real AOP proxified cacheable bean method {#link #createClient}.
*
* #see Spring Cache #Cacheable - not working while calling from another method of the same bean
* #see Spring cache #Cacheable method ignored when called from within the same class
*/
#EnableCaching
#CacheConfig(cacheNames = "ClientFactoryCache")
static class FactoryInternalCache {
#Cacheable(sync = true)
public Client createClient(#Nonnull ClientConfig clientConfig) {
return ClientCreationUtils.createClient(clientConfig);
}
}
}
I would like to share what I think is the easiest approach:
Autowire the controller and use to call the method it instead of using the class context this.
The updated code would look like:
#Controller
public class TestController {
#Autowired TestController self;
#RequestMapping("/test")
public String testView(){
self.expensiveMethod();
return "test";
}
#Cacheable("ones")
public void expensiveMethod(){
System.out.println("Cache is not being used");
}
}
The default advice mode for processing caching annotation is “proxy”. At the startup of an application, all the caching annotations like #Caching, #Cacheable, #CacheEvict etc. are scanned and a target proxy class is generated for all of these classes. The proxy allows for intercepting the calls to these cacheable methods, which adds the caching advice/behavior.
So when we invoke the cacheable methods from the same class, as shown below, calls from the clients don’t get intercepted in a way that allows for caching advice to be added to them. Hence, every single time there is an unexpected cache miss.
Solution: Invoke the Cacheable methods from a different bean to use proxy class with caching advice.