基于注解式声明Aspectj实例分析
AOP描述
与基于代理类的AOP时限相比。基于xml的声明式Aspectj要便捷的多,但是它也存在这一些缺点,那就是要在spring文件中配置大量的代码信息。为了解决这个问题,Aspectj框架为AOP的实现提供了一套注解,用以取代spring配置文件中为实现AOP功能所配置的臃肿代码。
Aspectj的注解介绍及描述
案例分析
用idea创建一个maven模块,项目结构如下:
编写要通知的对象
在java目录下创建包,首先创建接口UserDao
package com.chen.jdk;
public interface UserDao {
public void addUser();
public void deleteUser();
}
接在在impl目录中创建接口的实现类UserDaoImpl
package com.chen.jdk.impl;
import com.chen.jdk.UserDao;
import org.springframework.stereotype.Repository;
@Repository("userDao")
public class UserDaoImpl implements UserDao {
@Override
public void addUser() {
System.out.println("添加用户");
}
@Override
public void deleteUser() {
System.out.println("删除用户");
}
}
@Repository注解
spring中的注解,@Repository用于标注数据访问组件,即DAO组件。例:
@Repository
public class VentorDaoImpl implements iVentorDao {
}
在一个稍大的项目中,如果组件采用xml的bean定义来配置,显然会增加配置文件的体积,查找以及维护起来也不太方便。
Spring2.5为我们引入了组件自动扫描机制,他在类路径下寻找标注了上述注解的类,并把这些类纳入进spring容器中管理
它的作用和在xml文件中使用bean节点配置组件时一样的。要使用自动扫描机制。
也就是说,它所注解的类会交由spring容器管理,就像我们把对象交由spring管理一样。在spring中对象就是那些配置文件中的bean。
applicationContext配置文件中配置了UserDao实现类的bean就不用这个注解了。
编写切面通知类
package com.chen.aspectj.annotation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
/**
* 切面类,用来编写通知
*/
@Aspect
@Component
public class MyAspect {
//定义切入点表达式
@Pointcut("execution(* com.chen.jdk.*.*(..))")
//使用一个返回值为void、方法体为空的方法来命名切入点
private void myPointCut(){}
//前置通知
@Before("myPointCut()")
public void myBefore(JoinPoint joinPoint){
System.out.println("前置通知:模拟执行权限检查....");
System.out.println("目标类是:"+joinPoint.getTarget());
System.out.println(",被植入增强处理的目标方法为:"+joinPoint.getSignature().getName());
}
//后置通知
@AfterReturning("myPointCut()")
public void myAfterReturning(JoinPoint joinPoint){
System.out.println("后置通知:模拟日志记录...");
System.out.println(",被植入增强处理的目标方法为:"+joinPoint.getSignature().getName());
}
}
切入点表达式,是指的是在这个路径下的任何目录任何方法都会被通知,这里有前置通知和后置通知
编写配置
在recourses下面创建applicationContext.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<!--把对象UserDao和的创建交由spring管理-->
<bean id="userDao" class="com.chen.jdk.impl.UserDaoImpl"/>
<bean id="myAspect" class="com.chen.aspectj.annotation.MyAspect"/>
<!--指定要扫描的包,让注解生效-->
<context:component-scan base-package="com.chen"/>
<!--启动基于注解声明式Aspectj支持-->
<aop:aspectj-autoproxy/>
</beans>
把配置文件交给idea来管理
编写测试类
创建测试类
package com.chen.aspectj.annotation;
import com.chen.jdk.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAnnotationAspectj {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//1 从容器中获得内容
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
//2 执行方法
userDao.deleteUser();
}
}
测试结果
案例总结
案例中对UserDao的删除用户的方法进行前后通知。
spring中的bean可以帮我们管理对象,使用注解方式来实现aop的切面通知比jdk动态代理或者cglib代理或者xml方式实现通知要便捷得多。
首先有要通知的对象,然后有要通知的内容,即有切面类。
具体就是要通知那些方法,通知方式:前置通知还是后置通知,还是异常通知等等…
最后就是配置文件要添加,指定要扫描的包并且启动对于aspectj注解的支持。