I want to apply rate-limit on the basis of IP for each (/get)service for my project for e.g each IP can access each service for a particular no. of time i.e 5 times /10 second. I have used bucket4j rate-limiting but it's not working. Does anyone have any idea about it??
this is my application.properties
spring.cache.jcache.config=classpath:ehcache.xml
logging.level.org.ehcache=info
bucket4j.enabled=true
bucket4j.filters[0].cache-name=buckets
bucket4j.filters[0].filter-method=servlet
bucket4j.filters[0].url=.*
bucket4j.filters[0].rate-limits[0].bandwidths[0].capacity=5
bucket4j.filters[0].rate-limits[0].bandwidths[0].time=10
bucket4j.filters[0].rate-limits[0].bandwidths[0].unit=seconds
bucket4j.filters[0].rate-limits[0].expression="getRemoteAddress()"
bucket4j.filters[0].rate-limits[0].bandwidths[0].fixed-refill-interval=0
bucket4j.filters[0].rate-limits[0].bandwidths[0].fixed-refill-interval-unit=seconds
this is encache.xml
<config xmlns='http://www.ehcache.org/v3'
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jsr107="http://www.ehcache.org/v3/jsr107"
xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd
http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd">
<cache alias="buckets">
<expiry><ttl unit="seconds">6</ttl></expiry>
<heap unit="entries">2000</heap>
<jsr107:mbeans enable-statistics="true"/>
</cache>
</config>
pom.xml
<dependency>
<groupId>com.giffing.bucket4j.spring.boot.starter</groupId>
<artifactId>bucket4j-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<scope>runtime</scope>
</dependency>
server Initializer
#EnableCaching
public class ServletInitializer extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(EwseparationApplication.class);
}
}
I was having the same issue. It looks like there was an issue opened with the bucket4j spring boot starter github project about this (link).
I converted my application.properties to application.yml as the individual reported in the issue and my rate limit started working. I'm not sure what the actual issue is (why application.yml works and application.properties does not). I kindof prefer the properties format over yml.
you can use .yaml as .properties is still having some issue in recognizing the tags
I'm trying to intercept rest service calls with an aspect in the following manner
package mypackage.services.Service;
#Component
public class Service {
#Override
public Response helloService() {
return handleResult("Hello test " + new Date());
}
}
#Component
#Aspect
public class AuditLog {
#Before("execution(* mypackage.services.Service.*(..))")
public void beforeServcie(JoinPoint jp){
log.info("Before ",jp.getSignature().getName());
}
}
I'm using the following maven dependencies
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.10</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.10</version>
</dependency>
This maven plugin
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.0</version>
</plugin>
And my configuration xml contains
<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"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="mypackage"/>
<aop:aspectj-autoproxy proxy-target-class="true" />
also in the Application class I've added the following annotation
#Configuration
#EnableAspectJAutoProxy(proxyTargetClass=true)
public class Configuration{
...
}
On startup, by logging beans in the ApplicationContext, I can see that the aspect class "AuditLog" is being created.
I've set 2 breakpoints, but the debugger does not stop at the "beforeServcie" method but it does stop at the "helloService".
What am I missing?
Try this
execution(* mypackage.services.Service.*.*(..))
instead of
execution(* mypackage.services.Service.*(..))
If you are using spring-boot then instead of automatically adding dependency jars you can do
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
If you're using XML config <aop:aspectj-autoproxy ... /> then no need to have #EnableAspectJAutoProxy. It probably doesn't matter since AFAIK XML config wins over annotation config but better to avoid duplication
I am not quite sure why do you need aspectj-maven-plugin since Spring implements AOP by proxy and AFAIK this plugin is only needed for compile-time, post compile-time or load time weaving which are different concepts, see Spring AOP vs AspectJ
Now all the above mentioned points may not resolve your issue but the following might
execution(* mypackage.services.Service.Service.*(..))
And, don't set proxyTargetClass=true, let it be default false.
Explanation
The format is execution(<return type> <package name>.<class name>.<method name>(..)
The package name here is mypackage.services.Service and the class name is Service.
I am attempting to use the Spring/AspectJ integration with no luck. Spring version is 3.2.17 (yes, a bit old, I know).
Here is my relevant configuration:
pom.xml:
<!-- Spring dependencies, including spring-aspects -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.7.4</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.4</version>
</dependency>
applicationContext.xml:
<context:annotation-config/>
<aop:aspectj-autoproxy />
<bean id="loggingAspect" class="com.jason.app.web.util.logging.LoggingAspect" />
LoggingAspect.java (relevant class):
#Aspect
public class LoggingAspect {
private Logger log = LoggerFactory.getLogger(LoggingAspect.class);
/**
* Advice for before logging
* #param joinPoint
*/
#Before("execution(* com.jason.app.web.process..*(..))")
private void beforeAdvice(JoinPoint joinPoint) {
final String outputFormat = "intercept: executing method %s(%s)";
final String method =joinPoint.getSignature().getName();
List<?> argumentList = Collections.unmodifiableList(Arrays.asList(joinPoint.getArgs()));
final String formattedArguments = argumentList.stream().map(s -> s.toString()).collect(Collectors.joining(", "));
log.debug(String.format(outputFormat, method, formattedArguments));
}
}
I've pour over online tutorials, no luck. Can anyone point out what I did wrong?
Jason
The Spring configuration tag <aop:aspectj-autoproxy /> will enable Spring's proxy based AOP infrastructure, which only applies to Spring beans, and it does so using proxies with all the limitations of this solution compared to a pure AspectJ one.
Now if you want to go with AspectJ instead of Spring AOP, you will need to choose between compile-time weaving or load-time weaving. If you go with compile-time weaving, you need to add the aspectj-maven-plugin to your build. If you choose load-time-weaving, you'll need to run your JVM with a -javaagent:path/to/aspectjweaver.jar vm argument, as documented in AspectJ Documentation.
If you need to make your aspect post-processed by Spring (autowiring, etc), you need to list it in your Spring configuration. Aspects are singleton instances created outside of Spring, so you need to specify the static factory method aspectOf() to acess the single instance of the aspectj created by the AspectJ runtime.
<bean id="loggingAspect"
class="com.jason.app.web.util.logging.LoggingAspect"
factory-method="aspectOf"
/>
or the annotated way:
#Configuration
public class AspectConfig {
#Bean
public LoggingAspect loggingAspect() {
return LoggingAspect.aspectOf();
}
}
Don't forget to remove <aop:aspectj-autoproxy /> if you're not planning to use Spring AOP in addition to AspectJ. And why would you choose to do so, when AspectJ is so much more powerful?
you could add one more dependency
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
try, changing your point cut to
#Before("execution(* com.jason.app.web.process..*.*(..))")
( means advice will be applied to all public methods defined in the service package or a sub-package: com.jason.app.web.process )
change the expression to #Before("execution(public * your.package.YourClass.yourMethod(..))")
I have a collection of unmanaged classes that I are instantiated outside of Spring. I've been attempting to use Spring AOP with load time weaving to #Autowire a bean into these classes but have so far not had any luck.
I've been testing using Tomcat 8 and Spring Boot 1.2.0.
My #Configuration where I attempt to set up class looks like this:
#Configuration
#PropertySource("classpath:application.properties")
#EnableSpringConfigured
#EnableLoadTimeWeaving
public class Config
Inside Config I define the bean I want to #Auotwire into my unmanaged classes:
#Bean
public StateProvider stateProvider() {
//setup bean
return new DynamoStateProviderImpl( );
}
The unmanaged bean looks like this:
#Configurable(autowire = Autowire.BY_TYPE, dependencyCheck = true, preConstruction = true)
public class StateOutput implements UnifiedOutput {
#Autowired
private StateProvider stateProvider;
And I have the following deps inside my pom
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-agent</artifactId>
<version>2.5.6.SEC03</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
So far, I have not been able to see anything injected into stateProvider or been able to pull any info from the logs. I've also attempted setter style injection using
#Autowired
public void setStateProvider(StateProvider stateProvider){
this.stateProvider = stateProvider;
}
Thanks
In order to instrument LTW you'll need to either use the javaagent or place spring-tomcat-weaver.jar in the \lib folder and set up TomcatInstrumentableClassLoader in context.xml.
javaagent example:
-javaagent:"${settings.localRepository}/org/springframework/spring-agent/2.5.6.SEC03/spring-agent-2.5.6.SEC03".jar
ClassLoader example:
<Context>
<Loader loaderClass="org.springframework.instrument.classl oading.tomcat.TomcatInstrumentableClassLoader" />
</Context>
Starting from scratch without any previous Jersey 1.x knowledge, I'm having a hard time understanding how to setup dependency injection in my Jersey 2.0 project.
I also understand that HK2 is available in Jersey 2.0, but I cannot seem to find docs that help with Jersey 2.0 integration.
#ManagedBean
#Path("myresource")
public class MyResource {
#Inject
MyService myService;
/**
* Method handling HTTP GET requests. The returned object will be sent
* to the client as "text/plain" media type.
*
* #return String that will be returned as a text/plain response.
*/
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/getit")
public String getIt() {
return "Got it {" + myService + "}";
}
}
#Resource
#ManagedBean
public class MyService {
void serviceCall() {
System.out.print("Service calls");
}
}
pom.xml
<properties>
<jersey.version>2.0-rc1</jersey.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>${jersey.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-common</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jax-rs-ri</artifactId>
</dependency>
</dependencies>
I can get the container to start and serve up my resource, but as soon as I add #Inject to MyService, the framework throws an exception:
SEVERE: Servlet.service() for servlet [com.noip.MyApplication] in context with path [/jaxrs] threw exception [A MultiException has 3 exceptions. They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=MyService,parent=MyResource,qualifiers={}),position=-1,optional=false,self=false,unqualified=null,1039471128)
2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.noip.MyResource errors were found
3. java.lang.IllegalStateException: Unable to perform operation: resolve on com.noip.MyResource
] with root cause
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=MyService,parent=MyResource,qualifiers={}),position=-1,optional=false,self=false,unqualified=null,1039471128)
at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:74)
My starter project is available at GitHub: https://github.com/donaldjarmstrong/jaxrs
You need to define an AbstractBinder and register it in your JAX-RS application. The binder specifies how the dependency injection should create your classes.
public class MyApplicationBinder extends AbstractBinder {
#Override
protected void configure() {
bind(MyService.class).to(MyService.class);
}
}
When #Inject is detected on a parameter or field of type MyService.class it is instantiated using the class MyService. To use this binder, it need to be registered with the JAX-RS application. In your web.xml, define a JAX-RS application like this:
<servlet>
<servlet-name>MyApplication</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.mypackage.MyApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>MyApplication</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
Implement the MyApplication class (specified above in the init-param).
public class MyApplication extends ResourceConfig {
public MyApplication() {
register(new MyApplicationBinder());
packages(true, "com.mypackage.rest");
}
}
The binder specifying dependency injection is registered in the constructor of the class, and we also tell the application where to find the REST resources (in your case, MyResource) using the packages() method call.
First just to answer a comment in the accepts answer.
"What does bind do? What if I have an interface and an implementation?"
It simply reads bind( implementation ).to( contract ). You can alternative chain .in( scope ). Default scope of PerLookup. So if you want a singleton, you can
bind( implementation ).to( contract ).in( Singleton.class );
There's also a RequestScoped available
Also, instead of bind(Class).to(Class), you can also bind(Instance).to(Class), which will be automatically be a singleton.
Adding to the accepted answer
For those trying to figure out how to register your AbstractBinder implementation in your web.xml (i.e. you're not using a ResourceConfig), it seems the binder won't be discovered through package scanning, i.e.
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
your.packages.to.scan
</param-value>
</init-param>
Or this either
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>
com.foo.YourBinderImpl
</param-value>
</init-param>
To get it to work, I had to implement a Feature:
import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.ext.Provider;
#Provider
public class Hk2Feature implements Feature {
#Override
public boolean configure(FeatureContext context) {
context.register(new AppBinder());
return true;
}
}
The #Provider annotation should allow the Feature to be picked up by the package scanning. Or without package scanning, you can explicitly register the Feature in the web.xml
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>
com.foo.Hk2Feature
</param-value>
</init-param>
...
<load-on-startup>1</load-on-startup>
</servlet>
See Also:
Custom Method Parameter Injection with Jersey
How to inject an object into jersey request context?
How do I properly configure an EntityManager in a jersey / hk2 application?
Request Scoped Injection into Singletons
and for general information from the Jersey documentation
Custom Injection and Lifecycle Management
UPDATE
Factories
Aside from the basic binding in the accepted answer, you also have factories, where you can have more complex creation logic, and also have access to request context information. For example
public class MyServiceFactory implements Factory<MyService> {
#Context
private HttpHeaders headers;
#Override
public MyService provide() {
return new MyService(headers.getHeaderString("X-Header"));
}
#Override
public void dispose(MyService service) { /* noop */ }
}
register(new AbstractBinder() {
#Override
public void configure() {
bindFactory(MyServiceFactory.class).to(MyService.class)
.in(RequestScoped.class);
}
});
Then you can inject MyService into your resource class.
The selected answer dates from a while back. It is not practical to declare every binding in a custom HK2 binder.
I'm using Tomcat and I just had to add one dependency. Even though it was designed for Glassfish it fits perfectly into other containers.
<dependency>
<groupId>org.glassfish.jersey.containers.glassfish</groupId>
<artifactId>jersey-gf-cdi</artifactId>
<version>${jersey.version}</version>
</dependency>
Make sure your container is properly configured too (see the documentation).
Late but I hope this helps someone.
I have my JAX RS defined like this:
#Path("/examplepath")
#RequestScoped //this make the diference
public class ExampleResource {
Then, in my code finally I can inject:
#Inject
SomeManagedBean bean;
In my case, the SomeManagedBean is an ApplicationScoped bean.
Hope this helps to anyone.
Oracle recommends to add the #Path annotation to all types to be injected when combining JAX-RS with CDI:
http://docs.oracle.com/javaee/7/tutorial/jaxrs-advanced004.htm
Though this is far from perfect (e.g. you will get warning from Jersey on startup), I decided to take this route, which saves me from maintaining all supported types within a binder.
Example:
#Singleton
#Path("singleton-configuration-service")
public class ConfigurationService {
..
}
#Path("my-path")
class MyProvider {
#Inject ConfigurationService _configuration;
#GET
public Object get() {..}
}
If you prefer to use Guice and you don't want to declare all the bindings, you can also try this adapter:
guice-bridge-jit-injector
For me it works without the AbstractBinder if I include the following dependencies in my web application (running on Tomcat 8.5, Jersey 2.27):
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>${jersey-version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext.cdi</groupId>
<artifactId>jersey-cdi1x</artifactId>
<version>${jersey-version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>${jersey-version}</version>
</dependency>
It works with CDI 1.2 / CDI 2.0 for me (using Weld 2 / 3 respectively).
Dependency required for jersey restful service and Tomcat is the server.
where ${jersey.version} is 2.29.1
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>2.0.SP1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>${jersey.version}</version>
</dependency>
The basic code will be as follows:
#RequestScoped
#Path("test")
public class RESTEndpoint {
#GET
public String getMessage() {