学习Spring笔记五


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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章