`

2、spring-aop(Aspect Oriented Progroming )

    博客分类:
  • mvc
 
阅读更多
目标Target:就是通知织入的类主体。
连接点JoinPiont:每个方法都是一个连接点(方法调用前、方法调用后、方法异常、方法前后)
切点pointCut:并不是所用连接点都要织入通知,织入通知的连接点称为切点。
引介Introdution:特殊的通知,为目标类增加属性和方法。
通知Advice:通知是切点上织入的一段代码,(方法前通知、方法后通知、异常通知、前后环绕通知、引介)。
织入Weaving:将通知织入切点的过程;spring采用动态代理的方式,Aspectj采用编译期和类装载织入。
代理Proxy:代理类可能是与原类同接口的类,也可以是原类的子类。

package org.nick.test;  
import org.springframework.aop.framework.ProxyFactory;  
public class Test {  
    public static void main(String[] str){  
        //为目标类Waiter织入通知  
        //创建目标对象  
        Waiter target = new Waiter();  
        //创建通知类实例  
        MyBeforeMethod advice = new MyBeforeMethod();  
        //创建代理对象,接管目标对象  
        //这是spring提供的代理工厂类  
        ProxyFactory proxy = new ProxyFactory();  
        //设置要代理的目标类  
        //proxy将接管target的所用操作  
        proxy.setTarget(target);  
        //为代理对添加前置通知  
        proxy.addAdvice(advice);  
        //将设置好通知的代理对象返回给目标对象  
        target = (Waiter) proxy.getProxy();  
        //执行原有的方法  
        //这里是每个方法都设置的通知  
        target.sayHello("nick");  
                  
    }  
}  
  
  
package org.nick.test;  
public class Waiter {  
    public void sayHello(String name){  
        System.out.print("欢迎光临:"+name);  
    }  
    public void sayBye(String name){  
        System.out.println("下次再来:"+name);  
    }  
}  
  
  
package org.nick.test;  
import java.lang.reflect.Method;  
import org.apache.commons.httpclient.methods.GetMethod;  
import org.springframework.aop.MethodBeforeAdvice;  
public class MyBeforeMethod implements MethodBeforeAdvice {  
    //methodname   目标类的方法名  
    //methodargs   切点方法的参数  
    //typename     目标类  
    @Override  
    public void before(Method methodname, Object[] methodargs, Object typename)  
            throws Throwable {  
        //获取切点方法参数  
        System.out.println("下午好,第一个参数:"+methodargs[0]);  
        //获取切点的方法名  
        System.out.println("切点方法名:"+methodname.getName());      
        //获取目标类  
        System.out.println("目标类名:"+typename.toString());      
          
    }  
}  

下午好,第一个参数:nick
切点方法名:sayHello
目标类名:org.nick.test.Waiter@51a23566
欢迎光临:nick

基于beans.xml的前置通知 p73
关键:用一个接口接收代理对象,不然会报com.sun.proxy.$Proxy0 cannot be cast to org.nick.test.Person异常

           如果用类来接收,就需要在proxy下设置:p:proxyTargetClass ="true"   这样就不用实现BasePerson接口了,同时将使用CGLIB的代理方法而不是sun的代理方法,这两种代理方法在创建对象和代理对象运行效率上存在差异,一般将singleton对象设置为CGLIB代理,加快其运行效率。
            使用ProxyFactoryBean来创建代理对象实例,而java中使用的是ProxyFactory,实际上ProxyFactoryBean使用ProxyFactory方法创建的;
使用 p:interceptorNames 表示通知.类型可以是String[]型的,自动根据类型判定是前置或后置通知。p75

        和p:interfaces这里可以是多个接口,用<list><value>标签

<?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:p="http://www.springframework.org/schema/p"  
    xmlns:context="http://www.springframework.org/schema/context"  
    xmlns:aop="http://www.springframework.org/schema/aop"   
    xsi:schemaLocation="http://www.springframework.org/schema/beans   
       http://www.springframework.org/schema/beans/spring-beans-3.1.xsd  
       http://www.springframework.org/schema/context   
       http://www.springframework.org/schema/context/spring-context-3.1.xsd  
       http://www.springframework.org/schema/aop  
       http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">      
   <bean id="target" class="org.nick.test.Person"></bean>  
   <bean id="advice" class="org.nick.test.MyBeforeMethod"></bean>   
   <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"  
   p:interfaces="org.nick.test.BasePerson"  
   p:target-ref="target"  
   p:interceptorNames="advice"  
   />  
</beans>  
  
  
package org.nick.test;  
public interface BasePerson {  
    public void sayHello(String name);  
    public void sayBye(String name);  
}  
  
  
package org.nick.test;  
public class Person implements BasePerson {  
    @Override  
    public void sayHello(String name) {  
        System.out.println("你好:"+name);  
    }  
    @Override  
    public void sayBye(String name) {  
        System.out.println("再见:"+name);  
    }  
}  
  
  
package org.nick.test;  
import org.springframework.aop.framework.ProxyFactory;  
import org.springframework.context.ApplicationContext;  
import org.springframework.context.support.ClassPathXmlApplicationContext;  
public class Test2 {  
    public static void main(String[] str){  
        //加载beans.xml文件  
        ApplicationContext ac = new ClassPathXmlApplicationContext("conf/beans.xml");  
        BasePerson skx =(BasePerson) ac.getBean("proxy");  
        skx.sayHello("skx");  
    }  
} 


后置通知:实现AfterReturningAdvice接口
环绕通知:实现MethodInterceptor接口
唯一方法;invoke(MethodInvocation invocation)

Object[] args = invocation.getArguments();获取切点方法的参数,入参
Object obj  = invocation.proceed();
retrun obj;

在invocation.proceed()前的code在切点方法前执行,在之后的code在切点方法之后执行。
异常通知:实现ThrowsAdvice接口
自定义方法:必须名为afterThrowing(Method method,Object[] args,Object obj,Exception ex){}         切点方法、切点方法参数、目标对象、异常

                      或afterThrowing(Exception ex){}

前面都是对一个对象的所有方法进行了织入,实际中只需要对指定的方法作为切点:切点切面--->PointcutAdvisor
**************切点:对连接点定位,有选择性的对目标方法进行织入****************

定位:
通过ClassFilter定位目标类  p79
通过MethodMatcher定位目标方法
切面:通知+切点
1、静态方法切点:字符串匹配方法切点  &  正则表达式匹配方法切点
1.1、字符串匹配方法切点 继承StaticMethodMatcherPointcutAdvisor
现只对Waiter的sayBye方法进行织入:
现要对  目标对象、通知、切面、代理对象 进行配置
<bean id="target" class="org.nick.test.Waiter"></bean>      
   <bean id="advice" class="org.nick.test.MyBeforeMethod"></bean>   
      <!-- 切面是需要通知code,除了通知code也可以陪着target和class/interfces信息的,一般在proxy那里配置-->  
   <bean id="advisor" class="org.nick.test.StaticStringPointCut"  
    p:advice-ref="advice"  
   />   
   <!-- [color=green]引用切面,配置interceptorNames="切面"而不是通知了[/color] -->  
   <!-- "P:proxyTargetClass" associated with an element type "bean" is not bound. -->  
   <bean id="proxy"  class="org.springframework.aop.framework.ProxyFactoryBean"  
    p:interceptorNames="advisor"  
    p:target-ref="target"  
    p:proxyTargetClass="true"/>  
  
  
package org.nick.test;  
import java.lang.reflect.Method;  
import org.springframework.aop.ClassFilter;  
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;  
public class StaticStringPointCut extends StaticMethodMatcherPointcutAdvisor {  
    @Override  
    public boolean matches(Method arg0, Class<?> arg1) {  
        return  "sayBye".equals(arg0.getName());  
    }  
      //默认情况下,匹配所有类下的方法,这里增加一个ClassFilter只匹配Waiter下的方法  
    public ClassFilter getClassFilter(){  
        //复写其中的matches方法  
        return new ClassFilter(){  
            public boolean matches(Class clazz){  
                // Class1.isAssignableFrom(Class2)     
                //是用来判断一个类Class1和另一个类Class2是否相同或是另一个类的子类或接口。  
                return Waiter.class.isAssignableFrom(clazz);  
            }  
        };  
    }  
}  
  
  
package org.nick.test;  
import org.springframework.context.ApplicationContext;  
import org.springframework.context.support.ClassPathXmlApplicationContext;  
public class Test3 {  
    public static void main(String[] args) {  
        //加载beans.xml文件  
                ApplicationContext ac = new ClassPathXmlApplicationContext("conf/beans.xml");  
                Waiter skx =(Waiter) ac.getBean("proxy");  
                skx.sayHello("skx");  
                skx.sayBye("skx");  
    }  
}  

欢迎光临:skx
下午好:skx
切点方法名:sayBye
目标类名:org.nick.test.Waiter@4dea0aa2
下次再来:skx

这里就只对sayBye进行了织入;

正则表达式匹对方法:使用字符串匹对类和方法,书写的code较多,使用正则表达只需要配置xml就可以完成定位
<!-- 正则匹配方法 -->  
  <bean id="regexAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"  
   p:advice-ref="advice">  
   <property name="patterns">  
    <list>  
        <value>.*Hello.*</value>  
    </list>  
   </property>  
  </bean>  
  <!-- 引用切面,配置interceptorNames="切面"而不是通知了 -->  
  <!-- "P:proxyTargetClass" associated with an element type "bean" is not bound. -->  
  <bean id="proxy"  class="org.springframework.aop.framework.ProxyFactoryBean"  
   p:interceptorNames="regexAdvisor"  
   p:target-ref="target"  
   p:proxyTargetClass="true"/>  <!-- 正则匹配方法 -->  
  <bean id="regexAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"  
   p:advice-ref="advice">  
   <property name="patterns">  
    <list>  
        <value>.*Hello.*</value>  
    </list>  
   </property>  
  </bean>  
  <!-- 引用切面,配置interceptorNames="切面"而不是通知了 -->  
  <!-- "P:proxyTargetClass" associated with an element type "bean" is not bound. -->  
  <bean id="proxy"  class="org.springframework.aop.framework.ProxyFactoryBean"  
   p:interceptorNames="regexAdvisor"  
   p:target-ref="target"  
   p:proxyTargetClass="true"/>  



2、自动创建代理BeanPostProcessor
上面的每个对象都要创建一个代理对象,显得比较麻烦,这里将引入自动创建代理。

BeanNameAutoProxyCreator基于Bean配置的命名规则自动代理器,可以同时代理多个必须使用CGLIB代理
<bean id="target" class="org.nick.test.Waiter"></bean>      
<bean id="advice" class="org.nick.test.MyBeforeMethod"></bean>   


  <!--可以匿名创建-->  
  <bean id = "atuoProxy" class = "org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"  
     p:beanNames="*target"  
     p:interceptorNames = "advice"  
     />  
  
public static void main(String[] args) {  
    //加载beans.xml文件  
            ApplicationContext ac = new ClassPathXmlApplicationContext("conf/beans.xml");  
            //注意这里是直接将target取出来,就已经是代理好了的对象了
            Waiter skx =(Waiter) ac.getBean("target");  
            skx.sayHello("skx");  
            skx.sayBye("skx");  
} 


cglib自动创建代理:
 <bean id="target" class="org.nick.test.Waiter"></bean>    
   <bean id="ptarget" class="org.nick.test.Person"></bean>        
   <bean id="advice" class="org.nick.test.MyBeforeMethod"></bean>   
   <bean id = "atuoProxy" class = "org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"  
      p:beanNames="*target"  
      p:interceptorNames = "advice"  
      p:optimize="true"  
      />  
  
  
public static void main(String[] args) {  
        //加载beans.xml文件  
                ApplicationContext ac = new ClassPathXmlApplicationContext("conf/beans.xml");  
                //注意这里是直接将target取出来,就已经是代理好了的对象了  
                Waiter skx =(Waiter) ac.getBean("target");  
                Person nick =(Person) ac.getBean("ptarget");  
                skx.sayHello("skx");  
                nick.sayBye("nick");  
    } 


DefaultAdvisorAutoProxyCreator 基于切面Advisor的自动创建代理器
<bean id="target" class="org.nick.test.Waiter"></bean>    
   <bean id="ptarget" class="org.nick.test.Person"></bean>        
   <bean id="advice" class="org.nick.test.MyBeforeMethod"></bean>   
   <bean id="regexAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"  
    p:advice-ref="advice"  
    p:patterns=".*Hello.*"  
   />  
   <!-- 自动加载切面对象 -->  
   <bean id = "atuoProxy" class = "org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"  
   p:optimize="true"  
   />  
  
  
public static void main(String[] args) {  
                ApplicationContext ac = new ClassPathXmlApplicationContext("conf/beans.xml");  
                Waiter skx =(Waiter) ac.getBean("target");  
                Person nick =(Person) ac.getBean("ptarget");  
                skx.sayHello("skx");  
                nick.sayHello("nick");  
                skx.sayBye("skx");  
                nick.sayBye("nick");  
    }  


下午好:skx
切点方法名:sayHello
目标类名:org.nick.test.Waiter@6467b8ff
欢迎光临:skx
下午好:nick
切点方法名:sayHello
目标类名:org.nick.test.Person@690a614
你好:nick
下次再来:skx
再见:nick

切面正确加载!只对*hello方法织入
分享到:
评论

相关推荐

    spring,spring-aop-5.3.22.jar+aop+IDEA本地包

    Spring AOP provides an Alliance-compliant aspect-oriented programming implementation allowing you to define method interceptors and pointcuts to cleanly decouple code that implements functionality ...

    Spring-AOP.zip

    spring aop的具体实现与理论.AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构...

    Spring 2.5 Aspect-Oriented Programming

    The aim of Aspect-Oriented Programming (AOP) is not to replace Object-Oriented Programming (OOP), but to complement it, allowing you to create clearer and better structured programs. Gregor Kiczales,...

    CH03-AOP面向切面编程.pptx

    AOP(Aspect Oriented Programming):面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。 AOP是对OOP的补充,是软件开发中的一个热点,也是Spring框架中的一个重要内容。 利用AOP...

    Spring插件安装图解

    面向切面编程(AOP --- aspect oriented programming) 容器: Spring 是一个容器, 因为它包含并且管理应用对象的生命周期 框架: Spring 实现了使用简单的组件配置组合成一个复杂的应用. 在 Spring 中可以使用 XML 和 ...

    java、spring-boot、spring-tool-suite、maven、restful-api

    它包括IoC(Inverse of Control,控制反转)容器、AOP(Aspect-Oriented Programming,面向切面编程)等特性,可以简化开发过程、提高代码的可维护性和可测试性。 2. Spring MVC框架:Spring MVC是基于Spring框架的...

    Java - Spring-IoC(Inverse of Control)–> 控制反转

    一、Spring简介 1. 概述 Spring是一个轻量级Java开发框架(最早由Rod Johnson创建),为Java应用程序提供全面的基础架构支持。 Spring最根本的使命是解决企业级...② AoP(Aspect Oriented Programing) --&gt; 面向切面编程

    Spring面向切面编程AOP

    Spring,面向切面编程AOP例子!AOP(Aspect Oriented Programming)!

    pingone-customers-spring-boot-tools(95分以上课程大作业).zip

    它包括IoC(Inverse of Control,控制反转)容器、AOP(Aspect-Oriented Programming,面向切面编程)等特性,可以简化开发过程、提高代码的可维护性和可测试性。 2. Spring MVC框架:Spring MVC是基于Spring框架的...

    spring,aop解释

    AOP 是Aspect Oriented Programing 的简称,最初被翻译为“面向方面编程”,这个翻译向来为人所诟病,但是由于先入为主的效应

    Spring 2.5 aspect oriented programming

    engineers, and developers that want be able to write applications in a more modular and concise way, without learning Aspect or using languages other than Java and frameworks other than Spring.

    spring-boot 集成geotools工具包(高分项目).zip

    它包括IoC(Inverse of Control,控制反转)容器、AOP(Aspect-Oriented Programming,面向切面编程)等特性,可以简化开发过程、提高代码的可维护性和可测试性。 2. Spring MVC框架:Spring MVC是基于Spring框架的...

    进击的编程思想!带你学Spring AOP核心编程思想教程 新角度学面向切面编程

    AOP 的全称是“Aspect Oriented Programming”,即面向切面编程,它将业务逻辑的各个部分进行隔离,使开发人员在编写业务逻辑时可以专心于核心业务,从而提高了开发效率。AOP 采取横向抽取机制,取代了传统纵向继承...

    redis客户端工具, redis web客户端, redis web UI , spring-boot支持(高分项目).zip

    它包括IoC(Inverse of Control,控制反转)容器、AOP(Aspect-Oriented Programming,面向切面编程)等特性,可以简化开发过程、提高代码的可维护性和可测试性。 2. Spring MVC框架:Spring MVC是基于Spring框架的...

    springaop学习方法

    AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是...

    Spring开发指南

    Spring初探 准备工作 构建Spring基础代码 Spring 基础语义 ... Aspect Oriented Programming AOP 概念 AOP in Spring Dynamic Proxy 与Spring AOP CGLib 与 Spring AOP AOP 应用 DAO Support Remoting

    Aspectj in Action: Enterprise AOP with Spring Applications (2nd Edition)

    To allow the creation of truly modular software, OOP has evolved into aspect-oriented programming. AspectJ is a mature AOP implementation for Java, now integrated with Spring. AspectJ in Action, ...

    JAVA中spring介绍及心得.docx

    Spring框架的核心特点包括依赖注入(Dependency Injection)、面向切面编程(Aspect-Oriented Programming)、事务管理、模型-视图-控制器(Model-View-Controller,MVC)等。下面我会介绍一些关于Spring框架的核心...

    spring中AOP个人总结

    aop(aspect oriented programming)面向切面编程是spring当中一个重要内容,在学习之后感觉这个思想挺不错的,做个总结 AOP讲解 一、面向切面编程 ​ 听说过面向对象编程(oop),但是面向切面编程还真是第一次...

Global site tag (gtag.js) - Google Analytics