AOP中一些概念
Aspect(切面):指横切性关注点的抽象即为切面,它与类相似,只是两者的关注点不一样,类是对物体特征的抽象,而切面横切性关注点的抽象.
joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点,实际上joinpoint还可以是field或类构造器)
Pointcut(切入点):所谓切入点是指我们要对那些joinpoint进行拦截的定义.
Advice(通知):所谓通知是指拦截到joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知
Target(目标对象):代理的目标对象
Weave(织入):指将aspects应用到target对象并导致proxy对象创建的过程称为织入.
Introduction(引入):在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.
光看这些定义是很难理解的,所以需要在例子中去消化。
要进行AOP编程,首先我们要在spring的配置文件中引入aop命名空间:
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
</beans>
Spring提供了两种切面声明方式,实际工作中我们可以选用其中一种:
基于XML配置方式声明切面。
基于注解方式声明切面。
一,先来基于注解方式声明切面
1.Person类
package com.jzkangta.demo;
public class Person {
private int userId;
private String userName;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
2.代理对象类
package com.jzkangta.demo;
public class PersonService {
public void save(int userId,String userName){
System.out.println("save user ----->userId="+userId+",userName="+userName);
}
public void delete(int userId){
System.out.println("delete user ----->userId="+userId);
}
public void update(int userId,String userName){
System.out.println("update user ----->userId="+userId+",userName="+userName);
}
public Person find(int userId){
System.out.println("find user ----->userId="+userId);
return null;
}
}
3.切面类
package com.jzkangta.demo;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* 这是一个切面类
* 切面指横切性关注点的抽象即为切面,它与类相似,只是两者的关注点不一样,
* 类是对物体特征的抽象,而切面横切性关注点的抽象
* @author Administrator
*
*/
@Aspect //切面类需要用该注解标注
public class AspectClass {
//表达式详解需要查相关资料,这里不多说
@Pointcut("execution(* com.jzkangta.demo..*.*(..))")
/*
* 所谓切入点是指我们要对那些joinpoint进行拦截的定义
* 声明一个切入点(Pointcut),切入点是一个空的方法来声明的,后面对它的引用就用该方法名
*/
private void myPointcut() {}
/*
* 所谓通知是指拦截到joinpoint之后所要做的事情就是通知.
* 通知分为前置通知,后置通知,异常通知,最终通知,环绕通知
* 定义前置通知,可以传参数,具体请查相关资料
* myPointcut()为引用上面定义的切入点
*/
@Before("myPointcut()")
public void doAccessCheck() {
System.out.println("前置通知执行.......");
}
//后置通知,异常通知,最终通知,环绕通知,这里就不做演示
}
4.调用main方法
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"beans.xml"});
PersonService personService = (PersonService) ctx.getBean("personService");
personService.save(1, "jzkangta");
}
5.beans.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<!-- 启动对@AspectJ注解的支持 -->
<aop:aspectj-autoproxy/>
<!-- 注意personService不是一个接口 -->
<bean id="personService" class="com.jzkangta.demo.PersonService"></bean>
<!-- 将切面类也交给Spring -->
<bean id="aspectClass" class="com.jzkangta.demo.AspectClass"></bean>
</beans>
运行结果为:
前置通知执行.......
save user ----->userId=1,userName=jzkangta
二,先来基于XML声明切面
1.Person类,2.代理对象类都不用改
2.去掉了注解的切面类
package com.jzkangta.demo2;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* 这是一个切面类
* 切面指横切性关注点的抽象即为切面,它与类相似,只是两者的关注点不一样,
* 类是对物体特征的抽象,而切面横切性关注点的抽象
* @author Administrator
*
*/
public class AspectClass {
/*
* 所谓切入点是指我们要对那些joinpoint进行拦截的定义
* 声明一个切入点(Pointcut),切入点是一个空的方法来声明的,后面对它的引用就用该方法名
*/
private void myPointcut() {}
public void doAccessCheck() {
System.out.println("前置通知执行.......");
}
//后置通知,异常通知,最终通知,环绕通知,这里就不做演示
}
3.beans.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<!-- 注意personService不是一个接口 -->
<bean id="personService" class="com.jzkangta.demo2.PersonService"></bean>
<!-- 将切面类也交给Spring -->
<bean id="aspectClass" class="com.jzkangta.demo2.AspectClass"></bean>
<aop:config>
<aop:aspect id="myaop" ref="aspectClass">
<aop:pointcut id="mycut"
expression="execution(*com.jzkangta.demo2..*.*(..))" />
<!-- method="doAccessCheck"为切面类里的前置通知名 -->
<aop:before pointcut-ref="mycut" method="doAccessCheck" />
<!--
<aop:after-returning pointcut-ref="mycut"
method="后置通知名 " />
<aop:after-throwing pointcut-ref="mycut"
method="例外通知名" />
<aop:after pointcut-ref="mycut" method="最终通知名" />
<aop:around pointcut-ref="mycut" method="环绕的通知名" />
-->
</aop:aspect>
</aop:config>
</beans>
4.在用main方法执行后,结果如下:
前置通知执行.......
save user ----->userId=1,userName=jzkangta