zoukankan      html  css  js  c++  java
  • spring之AOP

    AOP(aspect oriented programming)面向切面编程

      1.aop概述

        aop简写aspect oriented programming,中文名字:面向切面编程;通过预编译方式和运行期动态代理实现程序功能的维护的一种技术,aop是oop的延续,aop是一个概念,并没有设定具体语言的实现,它能客服那些值有单继承特性语言的缺点.主要功能是日志记录,性能统计,安全控制,事务处理,异常处理等等.oop针对业务过程的实体及行为进行抽取封装,以获取更加清晰高效的逻辑单元划分.aop则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段已获得逻辑过程中个部分之间低耦合的隔离效果.这两种设计思想在目标上有本质的差异.ood/oop面向名领域,aop面向动词领域

        2.aop相关术语

    1.目标对象(target) 被代理的类(被增强的类)
    2.连接点(join point) 那些被拦截到的点,在spring中这些点指的是方法,因为spring只支持方法类型的连接点.
    3.切入点(pointcut) 

    表示一组连接点,这些连接点通过逻辑关系组合起来,或是通过通配,正则表达式等方式集中起来,它定义了项应的advice将要发生的地方

    我们对那些哪些方法进行拦截的定义.

    4.通知(advice)

    拦截到方法之后所要做的事情,通知分为前置通知,后置通知,异常通知,最终通知,环绕通知,

    advice定义了在pointcut里面定义的程序点具体要做的操作

    5.引介(introduction) 引介是一种特殊的通知,在不修改类代码的前提下,introduction可以在运行期为类动态地添加一些属性或方法
    6.切面(aspect)   是切入点和通知的结合
    7.织入(weaving)

    是一个过程,是将切面应用到目标对象从而创建出aop代理对象的过程,织入可以在编译期,类的加载期,运行期进行.

    spring采用的动态织入,而aspectj采用的织入方式为静态.

    8.代理(proxy) 一个类被aop织入增强后,就会产生一个结果代理类

        

        

       

     

      

      

      3.aop的底层实现,

        aop分为静态aop和动态aop

          静态aop:是将切面代码直接编译到java类中(espectj框架)

          动态aop:是将切面代码织入实现aop(JDK和cglib),织入只是一个过程(编译时期,类加载时期,运行时期),这个过程一般在运行时期,

      3.1    jdk代理工厂 (ProxyFactory) 

     1 public class ProxyFactory implements InvocationHandler{
     2     private Object target;
     3 
     4     public ProxyFactory(Object target) {
     5         super();
     6         this.target = target;
     7     }
     8     /*//创建代理对象  为了代理工厂的可扩展性 所以返回值为object   实现方法一   
     9     public Object createProxyFactory(){
    10         Object object = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),new ProxyClass(target));
    11         return object;
    12     }*/
    13      //实现方法二
    14     public Object createProxyFactory(){
    15         Object object = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
    16         return object;
    17     }
    18     @Override
    19     public Object invoke(Object proxy, Method method, Object[] args)
    20             throws Throwable {
    21         System.out.println("rizhi");
    22         return method.invoke(target, args);
    23     }
    24 }
    View Code

      IUserService接口

    public interface IUserService {
        public abstract void login();
    }
    View Code

      UserServiceImp类(IUserService的实现类)

    public class UserServiceImp implements IUserService{
        @Override
        public void login() {
            System.out.println("login....method...");
        }
    }
    View Code

      ProxyClass(实现方法一)

    public class ProxyClass implements InvocationHandler {
        private Object target;
        public ProxtClass(Object target) {
            this.target=target;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            System.out.println("日志文件");
            Object invoke = method.invoke(target, args);
            return invoke;
        }
    }
    View Code

      测试方法

      @Test
        public void test01(){
            IUserService iUserService=new UserServiceImp();
            ProxyFactory proxyFactory=new ProxyFactory(iUserService);
            IUserService ius = (IUserService) proxyFactory.createProxyFactory();
            ius.login();
        }
    View Code

      3.2     cglib代理工厂

    public class ProxyFactory implements MethodInterceptor{
        private Object target;
    
        public ProxyFactory(Object target) {
            super();
            this.target = target;
        }
        public Object createProxyFactory(){
            //创建enhancer
            Enhancer enhancer=new Enhancer();
            //创建目标对象
            enhancer.setSuperclass(target.getClass());
            //设置回调操作
            enhancer.setCallback(this);
            return enhancer.create();
        }
        @Override
        public Object intercept(Object arg0, Method method, Object[] arg2,
                MethodProxy arg3) throws Throwable {
            System.out.println("日志cglib");
            return method.invoke(target, arg2);
        }
    }
    View Code

        4.spring aop传统编程

      包结构:

       IUserService接口

    public interface IUserService {
        public abstract void login();
        public abstract void add();
        public abstract void del();
    }
    IUserService 

        UserServiceImp实现类

    public class UserServiceImp implements IUserService{
        @Override
        public void login() {
            System.out.println("login....method...");
        }
        @Override
        public void add() {
            System.out.println("add");
        }
        @Override
        public void del() {
            System.out.println("del");
        }
    }
    UserServiceImp

        UserHelp类

    public class UserHelp implements MethodBeforeAdvice,AfterReturningAdvice,org.aopalliance.intercept.MethodInterceptor{
        @Override
        public void before(Method arg0, Object[] arg1, Object arg2)
                throws Throwable {
            System.out.println("前置通知");
        }
        @Override
        public void afterReturning(Object arg0, Method arg1, Object[] arg2,
                Object arg3) throws Throwable {
            System.out.println("后置通知");
        }
        @Override
        public Object invoke(MethodInvocation mi) throws Throwable {
            System.out.println("环绕前");
            Object proceed = mi.proceed();
            System.out.println("环绕后");
            return proceed;
        }
    }
    UserHelp

        applicationContext.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:c="http://www.springframework.org/schema/c"
        xmlns:p="http://www.springframework.org/schema/p"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                            http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/context
                            http://www.springframework.org/schema/context/spring-context.xsd
                            http://www.springframework.org/schema/aop
                            http://www.springframework.org/schema/aop/spring-aop.xsd
                            http://www.springframework.org/schema/tx 
                            http://www.springframework.org/schema/tx/spring-tx.xsd">
        
           <!--定义目标类target  -->
        <bean id="userService" class="com.baidu.aop.demo.UserServiceImp"></bean>
        <!-- 通知advice -->
        <bean id="userServiceadvice" class="com.baidu.aop.demo.UserHelp"></bean>
        <!-- 切点 pointcut-->
        <bean id="userServicePointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">
            <property name="mappedNames">
                <list>
                    <value>add</value>
                    <value>login</value>
                </list>
            </property>
        </bean>
        <!-- 切面    advice+pointcut-->
        <bean id="userServiceAspect" class="org.springframework.aop.support.DefaultPointcutAdvisor">
            <property name="advice" ref="userServiceadvice"></property>
            <property name="pointcut" ref="userServicePointcut"></property>
        </bean>
        <!-- 代理 -->
           <bean id="userServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
                   <property name="target" ref="userService"></property>
                   <property name="interceptorNames" value="userServiceAspect"></property>
                   <property name="proxyInterfaces" value="com.baidu.aop.demo.IUserService"></property>
           </bean>
           
           <!-- <import resource="./aop1.xml"/> -->
    </beans>
    View Code

        测试类

    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations="classpath:applicationContext.xml")
    public class AopTest {
        
        @Autowired
        @Qualifier("userServiceProxy")
        private IUserService userService;
        @Test
        public void test01(){
            userService.login();
            System.out.println("------------");
            userService.add();
            System.out.println("-----------");
            userService.del();
        }
    }
    AopTest

        测试结果:

    环绕前
    前置通知
    login....method...
    后置通知
    环绕后
    ------------
    环绕前
    前置通知
    add
    后置通知
    环绕后
    -----------
    del
    测试结果

        基于aspectj切面传统开发

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:c="http://www.springframework.org/schema/c"
        xmlns:p="http://www.springframework.org/schema/p"
        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.xsd
                            http://www.springframework.org/schema/context
                            http://www.springframework.org/schema/context/spring-context.xsd
                            http://www.springframework.org/schema/aop
                            http://www.springframework.org/schema/aop/spring-aop.xsd
                            http://www.springframework.org/schema/aop 
                            http://www.springframework.org/schema/aop/spring-aop.xsd
                            http://www.springframework.org/schema/tx 
                            http://www.springframework.org/schema/tx/spring-tx.xsd">
        
           <!--定义目标类target  -->
        <bean id="userService" class="com.baidu.aop.demo.UserServiceImp"></bean>
        <!-- 通知advice -->
        <bean id="userServiceadvice" class="com.baidu.aop.demo.UserHelp"></bean>
            <!-- 切面你与切点的声明 -->
        <aop:config>    
                 
                <!-- 定义切点 -->
                <aop:pointcut expression="execution(* com.baidu.aop.demo.IUserService.*(..))" id="userServicePointcut"/>
                   <!--定义切面-->
                <aop:advisor advice-ref="userServiceadvice" pointcut-ref="userServicePointcut"/>
        </aop:config>
        
        
        
    </beans>
    applicationContext.xml

      测试类

    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations="classpath:applicationContext.xml")
    public class AopTest {
        
        @Autowired
        //@Qualifier("userServiceProxy")注释掉
        private IUserService userService;
        @Test
        public void test01(){
            userService.login();
            System.out.println("------------");
            userService.add();
            System.out.println("-----------");
            userService.del();
        }
    }
    AopTest

        5.spring 整合aspectj框架实现aop

     applicationContext.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:c="http://www.springframework.org/schema/c"
        xmlns:p="http://www.springframework.org/schema/p"
        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.xsd
                            http://www.springframework.org/schema/context
                            http://www.springframework.org/schema/context/spring-context.xsd
                            http://www.springframework.org/schema/aop
                            http://www.springframework.org/schema/aop/spring-aop.xsd
                            http://www.springframework.org/schema/aop 
                            http://www.springframework.org/schema/aop/spring-aop.xsd
                            http://www.springframework.org/schema/tx 
                            http://www.springframework.org/schema/tx/spring-tx.xsd">
        
           <!--定义目标类target  -->
        <bean id="userService" class="com.baidu.aop.spring_aspectj.UserServiceImp"></bean>
        <!-- 通知advice -->
        <bean id="userServiceadvice" class="com.baidu.aop.spring_aspectj.UserHelp"></bean>
            <!-- 切面你与切点的声明 -->
        <aop:config>    
                <!-- 定义切点 -->
                 <aop:pointcut expression="execution(* com.baidu.aop.spring_aspectj.IUserService.*(..))" id="userServicePointcut"/>
                <aop:aspect ref="userServiceadvice">
                    <aop:before method="before" pointcut-ref="userServicePointcut"/>
                    <aop:after-returning method="afterReturning" pointcut-ref="userServicePointcut" returning="value"/>
                    <aop:around method="around" pointcut-ref="userServicePointcut" /> 
                </aop:aspect>
        </aop:config>
    </beans>
    applicationContext.xml  

      IUserService接口

    public interface IUserService {
        public abstract String login();
        public abstract void add();
        public abstract void del();
    }
    IUserService

      UserServiceImp实现类

    public class UserServiceImp implements IUserService{
        @Override
        public String  login() {
            System.out.println("login....method...");
            return "123";
        }
        @Override
        public void add() {
            System.out.println("add");
        }
        @Override
        public void del() {
            System.out.println("del");
        }
    }
    UserServiceImp  

      UserHelp类

    public class UserHelp{
        public void before(JoinPoint jp){
            System.out.println("前置通知");
            System.out.println("拦截目标类"+jp.getSignature().getDeclaringTypeName());
            System.out.println("拦截方法名称"+jp.getSignature().getName());
        }
        public void afterReturning(JoinPoint jp,Object value){
            System.out.println("后置通知");
            System.out.println("返回值"+value);
        }
        public Object around(ProceedingJoinPoint mi) throws Throwable{
            System.out.println("环绕前");
            Object proceed = mi.proceed();
            System.out.println("环绕后");
            return proceed;
        }
    }
    UserHelp

      测试类

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations="classpath:applicationContext.xml")
    public class AopTest {
        
        @Autowired
        private IUserService userService;
        @Test
        public void test01(){
            userService.login();
            System.out.println("------------");
            userService.add();
            System.out.println("-----------");
            userService.del();
        }
    }
    AopTest

      输出结果:

    前置通知
    拦截目标类com.baidu.aop.spring_aspectj.IUserService
    拦截方法名称login
    环绕前
    login....method...
    环绕后
    后置通知
    返回值123
    ------------
    前置通知
    拦截目标类com.baidu.aop.spring_aspectj.IUserService
    拦截方法名称add
    环绕前
    add
    环绕后
    后置通知
    返回值null
    -----------
    前置通知
    拦截目标类com.baidu.aop.spring_aspectj.IUserService
    拦截方法名称del
    环绕前
    del
    环绕后
    后置通知
    返回值null
    result

      

            传统的方法实现aop开发:  在开发过程中applicationContext.xml配置文件中的配置项太多,eg:目标类,通知,切点,切面,代理,都需要我们去配置,

        基于传统的aspectj实现aop思想:  在开发过程中applicationContext.xml配置文件中简化了许多,使用<aop:config></aop:config>标签来配置切点切面代理进行配置

              aspectj的主要标签

    <aop:config>      来声明要对 aop 进行配置
    <aop:pointcut>     它是用于声明切点(简单说就是对哪些方法进行拦截)
    <aop:advisor>       定义传统的 aop 的切面,传统的 aop 切面它只能包含一个切点与一个增强
    <aop:aspect>      定义 aspectj 框架的切面.,它可以包含多个切点与多个通知

       spring框架整合aspectj实现aop思想:  在整合的过程中对于代理类中进行了修改,不需要继承或实现一些接口,降低了耦合性.在开发中很实用.

    6.基于注解开发aop

    applicationContext.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:c="http://www.springframework.org/schema/c"
        xmlns:p="http://www.springframework.org/schema/p"
        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.xsd
                            http://www.springframework.org/schema/context
                            http://www.springframework.org/schema/context/spring-context.xsd
                            http://www.springframework.org/schema/aop
                            http://www.springframework.org/schema/aop/spring-aop.xsd
                            http://www.springframework.org/schema/aop 
                            http://www.springframework.org/schema/aop/spring-aop.xsd
                            http://www.springframework.org/schema/tx 
                            http://www.springframework.org/schema/tx/spring-tx.xsd">
        <!-- 扫描spring注解 -->
        <context:component-scan base-package="com.baidu"></context:component-scan>
        <!-- 开启aspectj自动注解扫描 -->
        <aop:aspectj-autoproxy/>
    </beans>
    applicationContext.xml

     IUserService接口

    public interface IUserService {
        public abstract String login();
        public abstract void add();
        public abstract void del();
    }
    IUserService

    UserServiceImp实现类

    @Service
    public class UserServiceImp implements IUserService{
        @Override
        public String  login() {
            System.out.println("login....method...");
            return "123";
        }
        @Override
        public void add() {
            System.out.println("add");
        }
        @Override
        public void del() {
            System.out.println("del");
        }
    }
    UserServiceImp

    UserHelp增强类

    @Component
    @Aspect        //声明切面
    public class UserHelp{
        @Before("execution(* com.baidu.aop.spring_anno_aspectj.IUserService.*(..))")
        public void before(JoinPoint jp){
            System.out.println("前置通知");
            System.out.println("拦截目标类"+jp.getSignature().getDeclaringTypeName());
            System.out.println("拦截方法名称"+jp.getSignature().getName());
        }
        @AfterReturning(value="execution(* com.baidu.aop.spring_anno_aspectj.IUserService.*(..))",returning="value")
        public void afterReturning(JoinPoint jp,Object value){
            System.out.println("后置通知");
            System.out.println("返回值"+value);
        }
        @Around("execution(* com.baidu.aop.spring_anno_aspectj.IUserService.*(..))")
        public Object around(ProceedingJoinPoint mi) throws Throwable{
            System.out.println("环绕前");
            Object proceed = mi.proceed();
            System.out.println("环绕后");
            return proceed;
        }
    }
    UserHelp

     测试类

    @RunWith(SpringJUnit4ClassRunner.class)  //整合junit4
    @ContextConfiguration(locations="classpath:applicationContext.xml")//使用注解加载配置文件
    public class AopTest {
        
        @Autowired //依赖注入
        private IUserService userService;
        @Test
        public void test01(){
            userService.login();
            System.out.println("------------");
            userService.add();
            System.out.println("-----------");
            userService.del();
        }
    }
    AopTest

     测试结果

    环绕前
    前置通知
    拦截目标类com.baidu.aop.spring_anno_aspectj.IUserService
    拦截方法名称login
    login....method...
    环绕后
    后置通知
    返回值123
    ------------
    环绕前
    前置通知
    拦截目标类com.baidu.aop.spring_anno_aspectj.IUserService
    拦截方法名称add
    add
    环绕后
    后置通知
    返回值null
    -----------
    环绕前
    前置通知
    拦截目标类com.baidu.aop.spring_anno_aspectj.IUserService
    拦截方法名称del
    del
    环绕后
    后置通知
    返回值null
    result

      修改UserHelp增强类   把切点提取出来,只需要在切面上引用就可以

    @Component
    @Aspect        //声明切面
    public class UserHelp{
        @Pointcut("execution(* com.baidu.aop.spring_anno_aspectj.IUserService.*(..))")
        public void  mycut(){
            
        }
        
        @Before("mycut()")
        public void before(JoinPoint jp){
            System.out.println("前置通知");
            System.out.println("拦截目标类"+jp.getSignature().getDeclaringTypeName());
            System.out.println("拦截方法名称"+jp.getSignature().getName());
        }
        @AfterReturning(value="mycut()",returning="value")
        public void afterReturning(JoinPoint jp,Object value){
            System.out.println("后置通知");
            System.out.println("返回值"+value);
        }
        @Around("mycut()")
        public Object around(ProceedingJoinPoint mi) throws Throwable{
            System.out.println("环绕前");
            Object proceed = mi.proceed();
            System.out.println("环绕后");
            return proceed;
        }
    }
    UserHelp

    spring整合了aspectj框架他的底层代理方式默认为jdk代理方式来选择,如果没有接口则就是cglib代理方式.

    <aop:aspectj-autoproxy proxy-target-class="false"></aop:aspectj-autoproxy>
    

      

    Proxy-target-class 默认值是 false,代表的是如果目标是有接口的使用 proxy 代理,如果没有接
    口使用 cglib.
    如果将 proxy-target-class=true,不管目标是否有接口,都会使用 cglib 进行代理。
    

      

       

  • 相关阅读:
    SVN错误:Attempted to lock an already-locked dir
    DecimalFormat 中的 # 与 0 的区别(中文帮助文档中翻译可能是错误的)
    Logger.getLogger和LogFactory.getLog的区别
    在做excel导出时如何将excel直接写在输出流中
    10 -- 深入使用Spring -- 5... 实现任务的自动调度
    8 -- 深入使用Spring -- 8...2 管理Hibernate的SessionFactory
    8 -- 深入使用Spring -- 8...1 Spring提供的DAO支持
    8 -- 深入使用Spring -- 8... Spring整合Hibernate
    8 -- 深入使用Spring -- 7...4 使用自动装配
    8 -- 深入使用Spring -- 7...3 让Spring管理控制器
  • 原文地址:https://www.cnblogs.com/fjkgrbk/p/spring_aop.html
Copyright © 2011-2022 走看看