在上一个博客中我们是通过配置容器的方式实现对类进行AOP,来实现系统层面上的一些功能。
还有一种注解的方式,比之前的容器注入方式更方便一点。
首先跟之前一样创建一个Dao类:
public class CustomerDaoImpl implements CustomerDao {
@Override
public void save() {
System.out.println("保存客户。。。。");
}
@Override
public void update() {
System.out.println("修改客户。。。");
}
}
接下来为了要在CustomerDaoImpl某个方法前面添加日志功能,创建一个切面注解类:
@Aspect 注解是切面类 ,这里用的是@Before关键字
@Aspect //注解是切面类
public class MyAspectAnno {
/**
* 通知类型:@Before前置通知(切入点的表达式)
*/
@Before(value = "execution(public * com.Spring6AOP.CustomerDaoImpl.save())")
public void log() {
System.out.println("记录日志。。。");
}
}
再在容器中添加两个类的注入:这里必须开启自动代理,否则无法将切面类织入到CustomerDaoImpl类的方法中。
<!-- 开启自动代理 -->
<aop:aspectj-autoproxy />
<!--配置目标对象 -->
<bean id="customerDao" class="com.Spring6AOP.CustomerDaoImpl" />
<!-- 配置切面类 -->
<bean id="myAspectAnno" class="com.Spring6AOP.MyAspectAnno"></bean>
最后写出测试类:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext4.xml")
public class Demo1 {
@Resource(name="customerDao")
private CustomerDao customerDao;
@Test
public void run1() {
customerDao.save();
customerDao.update();
}
}
总结:
与前面的不同之处:
前面需要在容器中配置AOP如下:
<!-- 配置AOP -->
<aop:config>
<!-- 配置切面类:切入点+通知 -->
<aop:aspect ref="myAspectXml"> <!-- 引入切面类 -->
<!-- 配置的是前置通知,save方法执行之前,增强的方法会执行 -->
<!-- 切入点表达式:execution (public void com.Spring5AOP.CustomerDaoImpl.save()) -->
<!-- 1.execution() 固定的,不能不写
2.public 可以省略不写
3.void ,返回值可以出现*--->
<aop:before method="log" pointcut="execution (public void com.Spring5AOP.CustomerDaoImpl.save())"/>
</aop:aspect>
</aop:config>
其实 @Aspect //注解是切面类 就相当于下面这块
<aop:aspect ref="myAspectXml"> <!-- 引入切面类 -->
</aop:aspect
而@Before(value = "execution(public * com.Spring6AOP.CustomerDaoImpl.save())") 就相当于
<aop:before method="log" pointcut="execution (public void com.Spring5AOP.CustomerDaoImpl.save())"/>
两者达到的目的都是一样的。都是为了把切面类中的方法log 织入到Dao类的save 方法之前。
下面再看个通用的切入点测试:
如果我们在切面类里面需要加很多的通知类型,比如:Before,After,Around,等,那么就需要每次在注解那里写出类的全限定名,如:execution (public void com.Spring5AOP.CustomerDaoImpl.save()
我们可以自定义一个切入点,来简化以上的操作。方法很简单,就是自定义一个方法名(名称随意),然后在需要的日志方法上把value的值换成 类名.切入点方法名 即可。
@Aspect //注解是切面类
public class MyAspectAnno {
/**
* 通知类型:@Before前置通知(切入点的表达式)
*/
@Before(value = "MyAspectAnno.fn()")
public void log() {
System.out.println("记录日志。。。");
}
@After(value = "MyAspectAnno.fn()")
public void after() {
System.out.println("最终通知");
}
/*
* 自定义切入点 @Pointcut
*/
@Pointcut(value="execution(public * com.Spring6AOP.CustomerDaoImpl.save())")
public void fn() {}
}