I want to conditionally create an Aspect depending on a value read from the properties file. (It is related to profiling, that's why the intended selective use).
I have tried to create a class that implements Condition and therefore the matches() method that would allow me to perform the validation necessary and set the output to the corresponding Boolean, enabling or disabling it.
@Aspect
@Component
@Conditional(AuthFilterCondition.class)
public class AuthTokenFilter {
@Before("@annotation(org.company.annotations.ValidateAuthToken)")
public void doBefore(JoinPoint joinPoint) {
System.out.println("Loading auth token filter");
}
}
AuthFilterCondition
public class AuthFilterCondition implements Condition {
private static final String IS_AUTH_FILTER_FEATURE_ENABLED = "org.company.load.auth.filter";
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return (context.getEnvironment().getProperty(IS_AUTH_FILTER_FEATURE_ENABLED).equalsIgnoreCase("true"));
}
}
Controller
@Path("/v1")
@Produces({ MediaType.APPLICATION_JSON })
@Consumes({ MediaType.APPLICATION_JSON })
public interface HealthService {
@GET
@Path("/check/health")
Response checkHealth();
}
ServiceImpl
public class HealthServiceImpl implements HealthService {
@ValidateAuthToken
@Override
public Response checkHealth() {
return Response.ok().build();
}
}
servercontext.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxrs="http://cxf.apache.org/jaxrs" 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.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan
base-package="org.company" />
<import resource="classpath:/META-INF/cxf/cxf.xml" />
<import resource="classpath:/META-INF/cxf/cxf-servlet.xml" />
<import
resource="classpath*:META-INF/rcp/soa-interceptor-context.xml" />
<bean id="healthService"
class="org.company.services.impl.HealthServiceImpl" />
<bean class="org.company.services.filter.AuthTokenFilter" lazy-init="true">
<jaxrs:server address="/services">
<jaxrs:serviceBeans>
<ref bean="healthService" />
</jaxrs:serviceBeans>
</jaxrs:server>
<aop:aspectj-autoproxy />
</beans>
I'm already using an Aspect with Component to be detected during the component scan and the advise to be skipped if not matched, but it is still executing advise. Please suggest if I am doing something wrong here.
Here, I am passing a VM argument while running this which has the below value which will make AuthFilterCondition work.
-Dorg.company.load.auth.filter=true
Switching to annotation-based bean definitions like you did is probably the easiest solution. But if you have reasons to stick with XML, you could just use a Spring profile:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxrs="http://cxf.apache.org/jaxrs" 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.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<beans profile="auth-filter">
<bean class="org.company.service.filter.AuthTokenFilter" lazy-init="true"/>
</beans>
<beans>
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
<context:component-scan base-package="org.company"/>
<bean id="helloWorldService" class="org.company.service.impl.HelloWordServiceImpl"/>
<jaxrs:server id="restContainer" address="/">
<jaxrs:serviceBeans>
<ref bean="helloWorldService"/>
</jaxrs:serviceBeans>
</jaxrs:server>
<aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>
</beans>
Please note <beans profile="auth-filter">
.
Then, remove the @Component
and @Conditional
annotations from the aspect:
@Aspect
//@Component
//@Conditional(AuthFilterCondition.class)
public class AuthTokenFilter {
public static final String ACCESS_TOKEN_HEADER = "accessToken";
@Before("@annotation(org.company.service.annotation.ValidateAuthToken)")
public void doBefore(JoinPoint joinPoint) {
System.out.println("Reaching Aspect");
}
}
You also do not need the AuthFilterCondition
class anymore.
Next, e.g. on Windows when starting Tomcat, you can do this to activate the aspect:
xxx> set SPRING_PROFILES_ACTIVE=auth-filter
xxx> "%CATALINA_HOME%\bin\startup.bat"
To deactivate it, either never set the environment variable or unset it, if it is defined already:
xxx> set SPRING_PROFILES_ACTIVE=
xxx> "%CATALINA_HOME%\bin\startup.bat"