介绍
在开发中我们经常使用oop这种纵向结构来开发,但是却会出现一些横切的功能。譬如,日志记录的功能,我们需要在每个方法执行的详细信息通过日志记录,但是我们为每个方法去写日志,明显不合理。再如异常处理功能,我们需要在每个方法执行抛出的异常都专门处理都不合理。这样就需要AOP面向切面开发来处理横切问题。
AOP术语
- 通知:
通知主要是定义切面是什么以及何时使用。
Before:在接合点之前执行通知。
AfterReturning:在接合点执行完成之后执行通知。
AfterThrowing:如果从接合点抛出了任何异常,都执行通知。
After:接合点执行完成之后,无论是否抛出了异常,都执行通知。
Around:在接合点周围执行通知,意思就是可能在接合点之前执行,也可能在接合点之后执行。 - 连接点:
意思就是代码中的点,在这个点上开始玩切面。效果肯定是向应用程序中插入额外的逻辑。 - 切点:
用来选择需要执行一个或者多个连接点的表达式。 - 切面:
切面就是切点和通知的结合。 - 织入:
将方面与目标对象结合在一起的过程。 - 引入:
动态地为已经存在的类添加属性和方法。
XML方式实现AOP
配置文件:
<context:component-scan base-package="cn.spy"></context:component-scan>
<context:annotation-config></context:annotation-config>
<aop:config>
<aop:pointcut expression="execution(* cn.spy.service.impl.MyServiceImpl.*(..))" id="pc"/>
<aop:aspect ref="myAop">
<aop:before method="beforeExecute" pointcut-ref="pc"/>
<aop:after method="afterExecute" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
强制设置使用cglib代理:<aop:config proxy-target-class="true">
业务类和接口
public interface MyService {
public void serviceMed();
}
@Component("myService")
public class MyServiceImpl extends BaseLog implements MyService{
@Override
public void serviceMed() {
System.out.println("业务逻辑方法");
}
}
切面类:
@Component("myAop")
public class MyAop extends BaseLog {
public void beforeExecute() {
System.out.println("before execute");
}
public void afterExecute() {
System.out.println("after execute");
}
}
测试类:
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
MyService myService = (MyService) context.getBean("myService");
myService.serviceMed();
}
结果:
1.jpg
注解方式实现AOP
配置文件:
<context:component-scan base-package="cn.spy"></context:component-scan>
<context:annotation-config></context:annotation-config>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
切面类:
@Component("myAop")
@Aspect
public class MyAop extends BaseLog {
@Pointcut("execution(* cn.spy.service.impl.MyServiceImpl.*(..))")
public void cutMethod() {
}
@Before("cutMethod()")
public void beforeExecute() {
System.out.println("before execute");
}
@After("cutMethod()")
public void afterExecute() {
System.out.println("after execute");
}
}
强制使用cglib代理:@EnableAspectJAutoProxy(proxyTargetClass=true)
切点表达式
- 表达式语法:
execution(<scope> <return-type><fully-qualified-class-name>.*(parameters))
- 例子:
execution(* cn.spy.service.impl.MyServiceImpl.(..))
解释:匹配cn.spy.service.impl.MyServiceImpl类下的所有方法
execution(public void cn.spy.service.impl.MyServiceImpl.(..))
解释:匹配cn.spy.service.impl.MyServiceImpl类下的public void xx();方法。
execution(public void cn.spy.service.impl.MyServiceImpl.*(String,..))
解释:匹配cn.spy.service.impl.MyServiceImpl类下第一个参数为String类型,无返回值的所有公共方法。 - 通配符:
..该通配符匹配方法定义中的任何数量的参数。(也可以匹配任意数量的包)
+该通配符匹配给定类的任何子类。
*该通配符匹配任意数量的字符。
网友评论