@Aspect
@Component
public class AuditAspect {
@AfterReturning(value = "@annotation(audit)", returning = "returnParameter", argNames = "joinPoint, audit, returnParameter")
public void afterReturning(JoinPoint joinPoint, Audit audit, Object returnParameter) {
StringBuffer buffer = new StringBuffer();
for (Object object : joinPoint.getArgs()) {
if (null != object && "" != object) {
buffer.append(object.toString());
buffer.append(", ");
}
}
String outparam = null;
if (null != returnParameter && (returnParameter instanceof Map || returnParameter instanceof List)) {
outparam = "";
} else if (null != returnParameter) {
outparam = returnParameter.toString();
}
addAuditLog(joinPoint.getSignature().getName(),
buffer.toString(),
outparam,
this.userService.getLoggedinUser().getExternalId(),
String.valueOf(joinPoint.getStaticPart().getId()),
joinPoint.getTarget().toString(),
joinPoint.getStaticPart().getKind().toString());
logger.info("Ending Method: [" + joinPoint.getSignature().getName() + "]");
}
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.DEFAULT, rollbackFor = {HibernateException.class, AppException.class})
private void addAuditLog(String actionType, String metaDataIn, String metaDataOut, String actorId, String entityId, String entityName, String entityProperty) {
try {
AuditLog auditLog = new AuditLog();
auditLog.setRelevanceTime(new Timestamp(Calendar.getInstance().getTime().getTime()));
auditLog.setOperationType(actionType);
auditLog.setEntityPropertyNewValue(metaDataIn.length() > 255 ? metaDataIn.substring(0, 255) : metaDataIn);
auditLog.setEntityPropertyOldValue(metaDataOut.length() > 255 ? metaDataOut.substring(0, 255) : metaDataOut);
auditLog.setActorId(actorId);
auditLog.setEntityId(entityId);
auditLog.setEntityName(entityName);
auditLog.setEntityProperty(entityProperty);
this.daoFactory.getAuditLogDAO().makePersistent(auditLog);
} catch (Exception e) {
logger.error("Error occurred while adding audit log {}", e.toString());
}
}
@Before(value = "@annotation(com.nvsoft.csk.service.audit.Audit)", argNames = "joinPoint")
public void before(JoinPoint joinPoint) {
logger.info("Beginning method: [ " + joinPoint.getSignature().getName() + " ]");
}
@AfterThrowing(value = "@annotation(com.nvsoft.csk.service.audit.Audit)", throwing = "ex", argNames = "joinPoint, ex")
public void afterThrowing(JoinPoint joinPoint, Throwable ex) {
logger.info("Exception in method: [ " + joinPoint.getSignature().getName() + " ] Exception is: [" + ex.getMessage() + " ]");
}
public AuditInterceptor() {
logger.debug("Instantiating the AuditInterceptor");
}
@Autowired
public AuditInterceptor(DAOFactory daoFactory) {
this.daoFactory = daoFactory;
}
private DAOFactory daoFactory;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
private UserService userService;
public static Logger logger = LoggerFactory.getLogger(AuditInterceptor.class);
}
Create annotation with Audit
@Retention(value = RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Audit {
}
My ApplicationContext xml file looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="myDAOFactory" class="com.nvsoft.csk.dao.hibernate.HibernateDAOFactory">
<property name="sessionFactory">
<ref bean="serverSessionFactory"/>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="serverSessionFactory"/>
</bean>
<!--
Turn on AspectJ @Configurable support. As a result, any time you
instantiate an object, Spring will attempt to perform dependency
injection on that object. This occurs for instantiation via the "new"
keyword, as well as via reflection. This is possible because AspectJ
is used to "weave" applications at compile time. In effect
this feature allows dependency injection of any object at all in your
system, which is a very useful feature (without @Configurable you'd
only be able to dependency inject objects acquired from Spring or
subsequently presented to a specific Spring dependency injection
method). Applications use this useful feature in a number of
areas, such as @PersistenceContext injection into entities.
-->
<context:spring-configured/>
<!-- It will scan all annotated classes -->
<context:component-scan base-package="com.nvsoft.csk">
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
<!-- Annotation based transaction-->
<tx:annotation-driven transaction-manager="txManager"/>
<aop:aspectj-autoproxy/>
<!-- For hashing and salting user passwords -->
<bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder"/>
<bean id="saltSource" class="org.springframework.security.authentication.dao.ReflectionSaltSource"
p:userPropertyToUse="id"/>
<!-- Velocity Engine configuration for email template -->
<bean id="velocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean"
p:resourceLoaderPath="classpath:/emailTemplate/,classpath:/xhtmlTemplate/,classpath:/smsTemplate/"
p:preferFileSystemAccess="false"/>
<!-- mailSender properties -->
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"
p:host="${email.host}"
p:username="${user.email.address}"
p:password="${user.email.password}">
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.auth">${mail.smtp.auth}</prop>
<prop key="mail.smtp.starttls.enable">${mail.smtp.starttls.enable}</prop>
</props>
</property>
</bean>
<!-- Definition of template message if nothing is specified from the code then default properties are going to
pick from here -->
<bean id="templateMessage" class="org.springframework.mail.SimpleMailMessage"
p:from="${user.email.address}"
p:to="${user.email.address}"
p:subject="Greetings from S2Pay"/>
</beans>
I have Service class as CouponManager and i have annotated method createCoupon with @Audit and the aspect get trigger whenever i execute the createCoupon method and logs the information in the audittable
@Service("couponService")
public class CouponManager implements CouponService {
@Audit
@Transactional
@Override
public AbstractCoupon createCoupon(CouponForm form) {
//do whatever your businessLogic
return coupon;
}
}
Hope this information will helps whoever want to incorporate spring aspect oriented feature in their project