DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
Building Scalable Real-Time Apps with AstraDB and Vaadin
Register Now

Trending

  • An Overview of Kubernetes Security Projects at KubeCon Europe 2023
  • Is Podman a Drop-in Replacement for Docker?
  • 4 Expert Tips for High Availability and Disaster Recovery of Your Cloud Deployment
  • Web Development Checklist

Trending

  • An Overview of Kubernetes Security Projects at KubeCon Europe 2023
  • Is Podman a Drop-in Replacement for Docker?
  • 4 Expert Tips for High Availability and Disaster Recovery of Your Cloud Deployment
  • Web Development Checklist
  1. DZone
  2. Coding
  3. Frameworks
  4. JSR-299 CDI Interceptors for Spring Beans

JSR-299 CDI Interceptors for Spring Beans

Niklas Schlimm user avatar by
Niklas Schlimm
·
Aug. 19, 11 · Interview
Like (0)
Save
Tweet
Share
11.55K Views

Join the DZone community and get the full member experience.

Join For Free

Another early release of a Spring-CDI module, this time it's the interceptor pattern implementation. It implements a JSR-299 compliant interceptor binding model for Spring managed beans. We will use that in our business applications for cross-cutting-concerns.

Please notice: The intention of my blog is to share and discuss ideas. If you use any of this in your applications you're acting at your own risk.

JSR-299 interceptor pattern implementation

Features

The interceptor module provides the following features:

  • Use JSR-299 @Interceptor, @InterceptorBinding, @AroundInvoke and @Nonbinding annotations and their defined semantics in Spring managed beans
  • Support interceptors on the class level (applied to all declared methods) as well as on specific methods (method-level interceptors)
  • Support chains of multiple interceptors for the same target method
  • Support scoped target beans
  • Integrate with Spring AOP (CGLIB proxies only)

Interceptors for lifecycle event callbacks are supported since Spring 2.5 and are therefore not subject of this Sping-CDI module (@PostConstruct and @PreDestroy annotations).

This release of the Spring-CDI interceptor module does not support JSR318 @Interceptors annotation. The CDI spec states: "If an interceptor does not declare an @Interceptor annotation, it must be bound to beans using @Interceptors or ejbjar.xml." Because JSR299 specifies @InterceptorBinding as the binding mechanism I would not recommend to use @Interceptors annotation anymore.

Timeout interceptors and default interceptors are not yet supported.

Download Link

The Spring-CDI interceptor module is an usual Spring IoC-container extension delivered as JAR archive. You can download the module JAR and put that on the classpath of your Spring application.

Compiled Spring-CDI interceptor module JAR: Version 0.5.1

Sources: Version 0.5.1
API-Doc: Version 0.5.1

Everything is hosted on a git repository on Github.com.

Dependencies

Here are my runtime dependencies:

		<dependency>
			<groupid>org.springframework</groupid>
			<artifactid>spring-context</artifactid>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupid>org.springframework</groupid>
			<artifactid>org.springframework.aop</artifactid>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupid>javax.enterprise</groupid>
			<artifactid>cdi-api</artifactid>
			<version>1.0</version>
		</dependency>

		<dependency>
			<groupid>org.jboss.spec.javax.interceptor</groupid>
			<artifactid>jboss-interceptors-api_1.1_spec</artifactid>
			<version>1.0.0.Final</version>
		</dependency>

		<dependency>
			<groupid>cglib</groupid>
			<artifactid>cglib</artifactid>
			<version>2.2.2</version>
		</dependency>

Configuration

If the Spring-CDI interceptor module JAR and its dependencies are on your classpath, all you need to do is:

(1) register InterceptorAwareBeanFactoryPostProcessor in your application context
(2) define an include-filter to include javax.interceptor.Interceptor as component annotation in your context:component-scan tag

<beans>
...
<context:component-scan base-package="com.schlimm.springcdi.interceptor.simple" scoped-proxy="targetClass">
<context:include-filter type="annotation" expression="javax.interceptor.Interceptor" />
</context:component-scan>

<bean class="com.schlimm.springcdi.interceptor.InterceptorAwareBeanFactoryPostProcessor"/>
...
</beans>

If you like to order your interceptors you need to configure the interceptorOrder property of InterceptorAwareBeanFactoryPostProcessor:

<bean class="com.schlimm.springcdi.interceptor.InterceptorAwareBeanFactoryPostProcessor">
<property name="interceptorOrder">
<list>
<value>com.schlimm.springcdi.interceptor.ct._91_C1.interceptors.TransactionInterceptor</value>
<value>com.schlimm.springcdi.interceptor.ct._92_C1.interceptors.OldSecurityInterceptor</value>
<value>com.schlimm.springcdi.interceptor.ct._92_C1.interceptors.VIPSecurityInterceptor</value>
<value>com.schlimm.springcdi.interceptor.ct._92_C1.interceptors.SecurityInterceptor</value>
</list>
</property>
</bean>

Use Case

The following code snippets show how you can use the interceptor pattern ones you have configured your Spring application as described above. For more complex scenarios see my unit test cases.

Let's assume you have a business interface called: Simple_MyServiceInterface

public interface Simple_MyServiceInterface {

	String sayHello();
	String sayHello(String what);
	String sayGoodBye();
	
}

This is your implementation of the service.

@Component
@ReturnValueAdopted
public class Simple_MyServiceInterface_Impl implements Simple_MyServiceInterface {

	@Override
	public String sayHello() {
		return "Hello";
	}

	@Override
	public String sayHello(String what) {
		return what;
	}

	@Override
	public String sayGoodBye() {
		return "Good bye";
	}

}

Notice the @ReturnValueAdopted annotation on the type level. It is an interceptor binding declaration:

@Inherited
@InterceptorBinding
@Target({TYPE, METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ReturnValueAdopted { }

This interceptor also declares the @ReturnValueAdopted interceptor binding which means the interceptor is applied to the Simple_MyServiceInterface_Impl.

@Interceptor @ReturnValueAdopted
public class Simple_MyInterceptor {

	@AroundInvoke
	public String extendReturnValueWithSomeNonsense(InvocationContext ctx) throws Exception {
		String result = null;
		ctx.getContextData().put("Some", "Nonsense");
		try {
			result = (String)ctx.proceed();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return result + "_hello_world";
	}
	
}

The @Interceptor annotation declares the class as an interceptor. It will intercept all method calls on the Simple_MyServiceInterface_Impl bean. More specifically it will extend the return values with "_hello_world". Also notice the context data written to the InvocationContext. This allows chains of interceptors to exchange context data.

You can now autowire the Simple_MyServiceInterface_Impl bean into arbitrary beans:

@ContextConfiguration("/test-context-interceptor-simple.xml")
@RunWith(SpringJUnit4ClassRunner.class)
@DirtiesContext
public class SimpleInterceptorTestCase {

	@Autowired // will be intercepted
	private Simple_MyServiceInterface someInterceptedBean;
	
	@Test
	public void testHelloWorldExtension() {
		Assert.assertTrue(someInterceptedBean.sayHello().equals("Hello_hello_world"));
	}
	
}

The injected bean will have the defined Simple_MyInterceptor applied. When the sayHello() method is called the interceptor will extend the return value with the "_hello_world" message.

How it works

The core is the InterceptorAwareBeanFactoryPostProcessor. It uses two strategies to implement the logic. The InterceptorResolutionLogic scans the application context for registered interceptors. The InterceptorOrderingStrategy implements the ordering of chained interceptors for a target method call. The result of the data collection within these two strategies is stored in the InterceptorMetaDataBean. The bean factory post processor also registers the InterceptorAwareBeanPostProcessor with creates a proxy for each intercepted bean. This proxy has the intercepted bean as target and the InterceptedBeanProxyAdvice as interceptor advice applied. This advice creates (and caches) the chains of user defined JSR299 interceptors for each unique method call. It retrieves the required meta data for chaining interceptors from the InterceptorMetaDataBean.


Try everything if you have some time left!

From http://niklasschlimm.blogspot.com/2011/08/jsr-299-cdi-interceptors-for-spring.html

Spring Framework CDI

Opinions expressed by DZone contributors are their own.

Trending

  • An Overview of Kubernetes Security Projects at KubeCon Europe 2023
  • Is Podman a Drop-in Replacement for Docker?
  • 4 Expert Tips for High Availability and Disaster Recovery of Your Cloud Deployment
  • Web Development Checklist

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com

Let's be friends: