一
AOP基本概念
连接点 joinpoint,相对应一个线程上的一个方法(AOP的核心功能就是植入代码,在点和点之间加入代码)
切入点 pointcut ,它是一个描述,描述连接点是怎样的连接,在连接点的前还是后切入,等等。切入点有个表达式,这样写:
切入点表达式:public String com.bjsxt.dao.*.add() 此表达式是用来描述一堆方法,是所有包下的add方法
public String com.bjsxt.dao.*.*(); 此表达式是说描述所有包下的所有方法
通 知Advice ,是在某个特定的连接点上执行的动作。包括before前置通知,after后置通知 和 around环绕通知
切 面Aspect ,连接点、切入点、通知三者合一切为一个切面。
目标对象Target Object,是你“切”哪个对象,相当于委托类
植入Weaving,制作代理的过程
小总结
JoinPoint连接点:业务流程当中的方法调用(普通的方法调用)
PointCut 切入点:利用一个表达式,描述多个连接点,将来会把代码植入到一些连接点上面(在配置文件中配置要切哪些方法)
Advice 通知:增强功能代码(代理类)
Aspect 切面
Target Object目标对象:委托类
Weaving 植入:制作代理的过程(Spring AOP制作代理类有两种方式:proxy,cglib,当你的类有接口用proxy,没有接口用cglib)
AOP实例代码——————————————
1.导入jar包
commons-loggin.jar
spring.jar
aspectjrt.jar(是面向切面编程的实现包,非spring原生,第三方,spring在它的基础上进行了封装,让用户使用更加便利)
aspectjweaver.jar
cglib-nodep-2.1.3.jar
spring-sources.jar
2.配置用xml方式,把所有的bean放到xml中做切面
applicationcontext.xml
<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-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<!-- AOP功能是基于IOC容器的。AOP只能给IOC容器内部的对象做代理。AOP这把刀只能切IOC容器中的对象 -->
<!-- 这里是把容器中的对象配置到容器当中,如下-->
<bean id="userDao" class="com.bjsxt.dao.UserDao"></bean>
<bean id="userAction" class="com.bjsxt.action.UserAction" >
<property name="userDao" ref="userDao" ></property>
</bean>
<bean id="logAdvice" class="com.bjsxt.advice.LogAdvice" ></bean>
<bean id="teacherDao" class="com.bjsxt.dao.TeacherDao" ></bean> <!--假如我是从项目中途加入的,另的aop不知道,可以直接写我自己的teacherDao。在Test.java中也要相应做修改-->
<bean id="myClassDao" class="com.bjsxt.dao.MyClassDaoImpl" ></bean> <!--这个程序员依然不知道前面人员写了什么,就这样加bean,这样是可以的,此bean对应下面的MyClassDaoImpl.java-->
<!--这里aop的配置如果注释掉,那么增强的功能将不会显示,太强了!相当于一个开关!spring果然强大-->
<!--这里定义切入点,连接点和通知的,有了这三样,就开始定义切面-->
<aop:config>
<aop:pointcut expression="execution(public * com.bjsxt.dao.*.*())" id="logCut" /> <!--这里是切入点,连接点就是已有的方法-->
<aop:aspect ref="logAdvice" > <!--通知,我们要增强的行为,这对应的是一个类LogAdvice.java,上面的bean有定义,相当于代理类-->
<aop:before method="aaa" pointcut-ref="logCut" />
<aop:after method="ccc" pointcut-ref="logCut" />
</aop:aspect>
</aop:config>
<!--AOP增强功能到这-->
</beans>
3.LogAdvice.java
public class LogAdvice{
public void aaa(){
System.out.println("委托类方法执行之前执行!!!");
}
public void ccc(){
System.out.println("委托类方法执行之后!!!");
}
}
4.Test.java
执行这个方法测试,这个test测试类就是客户类
public class Test{
public static void main(String[ ] args){
ApplicationContext ac = new ClassPathXmlApplicationContext(
new String[ ] {"applicationContext.xml"}
);
//测试代码一,测试一的时候把二、三注释掉
UserDao userDao = (UserDao) ac.getBean("userDao");
userDao.add();
//测试代码二,假定下面是你加入团队后新加的代码(练习时可注释掉)
TeacherDao teacherDao = (TeacherDao) ac.getBean("teacherDao");
System.out.println(teacherDao.getClass().getName);
teacherDao.add();
//end
//测试代码三
MyClassDao myClassDao = (MyClassDao) ac.getBean("myClassDao");
System.out.println(myClassDao.getClass().getName());
myClassDao.add();
myClassDao.del(); //如果执行结果只增强了add,而没有增强del方法,看看配置文件中aop的地方,com.bjsxt.dao.*.*()还是只*.add()
}
}
5.dao包下面建立接口MyClassDao.java
public interface MyClassDao{
void add();
void del();
}
6.dao包下面写实现类MyClassDaoImpl.java
public class MyClassDaoImpl implements MyClassDao{
public void add(){
System.out.println("MyClassDaoImpl.add()");
}
public void del(){
System.out.println("MyClassDaoImpl.del()");
}
}
———————示例end———————————————
二
通知的类型
1.前置通知 在某连接点之前执行的通知,但这个通知不能阻止连接点前的执行(除非它招聘一个异常)
2.返回后通知 在某连接点正常完成后执行的通知
3.抛出异常后通知 在方法抛出异常退出时执行的通知
4.后通知 当某连接点退出的时候执行的通知
5.环绕通知 包围一个连接点的通知,如方法调用。这是最强大的一种通知类型。环绕通知可以在方法调用前后完成自定义的行为。环绕通知相当于filter,前后都可以拦截,环 绕通知相当于前置通知+返回后通知,不同的需求,使用的通知不一样。
代码
LogAdvice.java
public class LogAdvice{
public void aaa(){
System.out.println("委托方法执行之前!!!");
}
public void ccc(){
System.out.println("委托方法执行之后!!!");
}
public Object around(ProceedingJoinPoint pjp){ //正在执行的JoinPoint连接点,意味着这个环绕通知环绕在正在执行的连接点(方法)外。pjp就是在拦截,或者是代理过程中,为通知,提供必要数据的抽象对象。有了数据后,就可以进行你想的操作了。pjp很重要。
System.out.println("委托类方法执行之前 !!!");
try{
//pjp.getArgs(); //获取客户类调用方法时,传递的参数
//pjp.getSignature().getName(); //获取客户类调用的方法的名字
//pjp.getTarget(); //获取委托类
System.out.println("委托类方法执行之前!!!");
Object result = pjp.proceed(); //和chain.doFilter()是一样的。
System.out.println("委托类方法执行之后!!!");
return result;
} catch(Throwable e) {
e.printStackTrace();
return null;
}
}
}
applicationContext.xml和上一个示例的一样,需要注意的重点如下
<aop:config>
<aop:pointcut expression = "execution ( public * com.bjsxt.dao.*.*() )" id="logCut" />
<aop:aspect ref="logAdvice" >
<aop:around method="around" pointcut-ref="logCut" />
</aop:aspect>
</aop:config>
————————示例代码end——————————————
数据+算法=程序
代理模式,责任链模式,装饰器模式它们很相似,但是各自有侧重点
代理模式重在访问控制
责任链模式重在信息过滤
装饰器模式重在功能增强 在IO流中有体现,buffer