AOP
在软件开发中,分布于应用中多处理的功能被称为横切关注点,通常,横切关注点从概念上讲是与应用逻辑相分离的,将横切关注点与业务逻辑相分离正是面向切面编程(AOP)要解决的问题.
依赖注入有利于对象之间的解耦,而AOP可以实现横切关注点与它们所影响的对象之间的解耦。横切关注点常常应用在日志、事务管理、缓存等。
在面向切面的编程中,横切点就是一个通用的功能,也可以称作为切面,该功能可以再任何地方使用,而无需修改受影响的类。这样做的好处:1.关注点集中一处,而不是分散开来2.服务模块简单化
AOP中的术语
切面(aspect):在应用程序中一个通用的功能
通知(advice):可以理解为是切面的一个具体实现,通常使用Java编写,常用的通知:前置通知(before)、后置通知(after)、环绕通知(around)、返回通知(after-returning)、异常通知(after-throwing)
切点(pointcut):指切面或者是通知所存在的位置,这个位置就是切点。
连接点(joinpoint):将通知放在切点的一个时机,例如:方法前、方法后等。
织入(weaving):将切面应用到目标对象创建新的代理对象的过程。
引入(introduction):允许我们向现有类添加新的属性或方法。主要通过创建通知来实现。
在Spring中需要使用AspectJ的切点表达式来编写切点。
其中execution指示器()是定义切点的最主要指示器,在此基础上联合其它的指示器来限定切点。
例如:execution(* aop.People.getName(..))
类People加上方法getName ,用(..)表示方法的参数,
“ * ”表示的是方法的任意返回类型.
execution(* aop.People.getName(..)) && within(aop1.*)
&&表示并且 ,aop1.*表示aop1包下的任意类方法,那么整个表达式表示当aop.People.getName(..)方法和aop1包下任意类的方法同时执行时,才会执行execution,即相应的通知。
类似的还有”||”、”!”符号。
在Spring中还有一个bean指示器,bean含有一个id号,用于限定bean。例如:execution(* aop.People.getName(..)) and bean(p)
AOP在XML中声明
实例:
package aop;
public class Advice {
public voiddoSomething()
{
System.out.println("hello.......");
}
}
package aop;
public class People {
private String name;
public String getName() {
return name;
}
public voidsetName(String name) {
this.name = name;
}
public String greet()
{
System.out.println(name+".............");
return name;
}
}
<bean id="p"class="aop.People">
<property name="name" value="zhangsan"></property>
</bean>
<bean id="method" class="aop.Advice"/>
<aop:config>
<aop:aspect ref="method">
<aop:pointcut expression="execution(* aop.People.greet()) and bean(p)"id="greet"/>
<aop:before method="doSomething" pointcut-ref="greet"/>
</aop:aspect>
</aop:config>
ApplicationContextac=new ClassPathXmlApplicationContext("aop/bean.xml");
People p=ac.getBean("p", People.class);
p.greet();
结果:hello .......
zhangsan.............
给通知传递参数
实例:
public class Advice {
private int id;
public voiddoSomething(int id)
{
System.out.println("hello......."+id);
}
}
public class People {
private String name;
public String getName() {
return name;
}
public voidsetName(String name) {
this.name = name;
}
public void greet(int id)
{
System.out.println(name+".............");
}
}
<bean id="p" class="aop.People">
<property name="name" value="zhangsan"></property>
</bean>
<bean id="method" class="aop.Advice"/>
<aop:config>
<aop:aspect ref="method">
<aop:pointcut expression="execution(* aop.People.greet(int)) and args(id)"id="greet"/>
<aop:before method="doSomething" pointcut-ref="greet" arg-names="id" />
</aop:aspect>
</aop:config>
</beans>
ApplicationContextac=new ClassPathXmlApplicationContext("aop/bean.xml");
People p=ac.getBean("p", People.class);
p.greet(1);
结果:hello .......1
zhangsan.............
由结果可知,目标方法中的参数id传给了通知。