AOP详解

 

  • AOP
  • Aop简介
  • 什么是AOP

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码,并在不修改原来代码的基础上加入了功能,经典应用:事务管理、性能监视、安全检查、缓存 、日志等,简而言之,

AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入。

  • Aop原理

AOP底层就是生成动态代理,如果被代理的有接口,就使用jdk动态代理生成代理对象,反之,就用cglib字节码增强生成代理对象

  • Aop术语

1.target:目标类,需要被代理的类。例如:UserService

2.Joinpoint(连接点):所谓连接点是指那些可能被拦截到的方法。例如:所有的方法

3.PointCut 切入点:被增强的连接点。例如:addUser()

4.advice 通知/增强,增强代码。例如:after、before

5. Weaving(织入):是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程.

6.proxy 代理类

7. Aspect(切面): 是切入点pointcut和通知advice的结合

       一个线是一个特殊的面。

       一个切入点和一个通知,组成一个特殊的

  • AOP手动实现
  • Jdk动态代理

编程

需要编程的类: 目标类(被代理的类),Advise类(加强类),工厂类(生成代理)

UserServiceImpl类(target)

/**

 * 代理类

 * @author Kuang

 *

 */

public class UserServiceImpl implements UserService {

 

    @Override

    public void addUser() {

       System.out.println("addUser");

      

    }

 

    @Override

    public void remvoeUser() {

       System.out.println("remvoeUser");     

    }

 

}

MyAspect类(advise)

public class MyAspect {

 

    public void before(){

       System.out.println("");

    }

    public void after(){

       System.out.println("");

    }

}

工厂类

public class MyFactory {

    //生成代理对象

    public static UserService createService(){

       //目标类

       UserService userService = new UserServiceImpl();

       //增强类

       MyAspect myAspect = new MyAspect();

       /*

        * 3 代理类:将目标类(切入点)和 切面类(通知) 结合 --> 切面

        * Proxy.newProxyInstance

        *     参数1loader ,类加载器,动态代理类 运行时创建,任何类都需要类加载器将其加载到内存。

        *         一般情况:当前类.class.getClassLoader();

        *                目标类实例.getClass().get...

        *     参数2Class[] interfaces 代理类需要实现的所有接口

        *         方式1:目标类实例.getClass().getInterfaces()  ;注意:只能获得自己接口,不能获得父元素接口

        *         方式2new Class[]{UserService.class}  

        *         例如:jdbc 驱动  --> DriverManager  获得接口 Connection

        *     参数3InvocationHandler  处理类,接口,必须进行实现类,一般采用匿名内部

        *         提供 invoke 方法,代理类的每一个方法执行时,都将调用一次invoke

        *            参数31Object proxy :代理对象

        *            参数32Method method : 代理对象当前执行的方法的描述对象(反射)

        *                执行方法名:method.getName()

        *                执行方法:method.invoke(对象,实际参数)

        *            参数33Object[] args :方法实际参数

        *

        */

       UserService proxyService = (UserService) Proxy.newProxyInstance(

              MyFactory.class.getClassLoader(),

              userService.getClass().getInterfaces(), new InvocationHandler() {

                 

                  @Override

                  public Object invoke(Object proxy, Method method, Object[] args)

                         throws Throwable {

                     myAspect.before();

                     System.out.println(method.getName()); //可用于过滤加强

                     method.invoke(userService, args);

                     myAspect.after();

                     return proxy;

                  }

              });

       return proxyService;

    }

}

测试结果:

 

  • CGlib字节码增强

CGlib字节码加强使用于目标类没有接口的情况,需要目标类,加强类(advise),工厂类(产生代理)

准备

添加jar包:cglib-2.2.jar 和 sm-3.3.jar

值得一提的是spring-core..jar已经包含了以上两个jar包。

编程

目标类(UserServiceImpl

/**

 * 被代理类(没有接口)

 * @author Kuang

 *

 */

public class UserServiceImpl{

 

    public void addUser() {

       System.out.println("addUser");

      

    }

 

    public void remvoeUser() {

       System.out.println("remvoeUser");     

    }

 

}

增强类(advice)

public class MyAspect {

 

    public void before(){

       System.out.println("");

    }

    public void after(){

       System.out.println("");

    }

}

工厂类

**

 * CGlib字节码加强

 * @author Kuang

 *

 */

 

public class MyFactory {

    //生成代理对象

    public static UserServiceImpl createService(){

       //目标类

       UserServiceImpl userService = new UserServiceImpl();

       //增强类

       MyAspect myAspect = new MyAspect();

       //CGlib加强主类

       Enhancer enhancer = new Enhancer();

       //设置父类

       enhancer.setSuperclass(userService.getClass());

       //jdk动态代理的InvocationHandlerinvoke方法类似

       enhancer.setCallback(new MethodInterceptor() {

          

           @Override

           public Object intercept(Object proxy, Method method, Object[] args,

                  MethodProxy methodProxy) throws Throwable {

              myAspect.before();

              Object obj = method.invoke(userService, args);

              myAspect.after();

              return obj;

           }

       });

       UserServiceImpl proxyService = (UserServiceImpl) enhancer.create();

       return proxyService;

    }

}

测试

    1. AOP联盟通知类型

AOP联盟为通知Advice定义了org.aopalliance.aop.AdviceSpring按照通知Advice在目标类方法的连接点位置,可以分为5类

(1)前置通知 org.springframework.aop.MethodBeforeAdvice在目标方法执行前实施增强

(2)后置通知 org.springframework.aop.AfterReturningAdvice在目标方法执行后实施增强

3)环绕通知 org.aopalliance.intercept.MethodInterceptor在目标方法执行前后实施增强

(4)异常抛出通知 org.springframework.aop.ThrowsAdvice在方法抛出异常后实施增强

(5)引介通知 org.springframework.aop.IntroductionInterceptor在目标类中添加一些新的方法和属性(一般没有用)

介绍AOP联盟的目的:替代增强类(advice)

例子:

Try{

   前置通知

   目标方法

   后置通知

}catch(){

   异常抛出通知

}

  • AOP半自动装配
  • 准备

准备jar包,分别为4+1 spring基本jar包, Aop联盟接口包,Aop联盟实现包

AOP详解_第1张图片

 

  • 编程

目标类接口 UserService

public interface UserService {

    void addUser();

    void remvoeUser();

}

目标类实现 UserServiceImpl

/**

 * 被代理类(目标类)

 * @author Kuang

 *

 */

public class UserServiceImpl implements UserService {

 

    @Override

    public void addUser() {

       System.out.println("addUser");

      

    }

 

    @Override

    public void remvoeUser() {

       System.out.println("remvoeUser");     

    }

}

切面类(增强类)MyAspect

/**

 * 增强类,实现环绕通知接口MethodInterceptor

 * @author Kuang

 *

 */

public class MyAspect implements MethodInterceptor{

 

    @Override

    public Object invoke(MethodInvocation mi) throws Throwable {

       System.out.println("前方法");

       Object object = mi.proceed(); //执行目标方法

       System.out.println("后方法");

       return object;

    }

}

  • 配置

xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

                      http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">

 

   

    <bean id="userServiceId" class="com.baidu.aop.banauto.UserServiceImpl">bean>

   

    <bean id="myAspectId" class="com.baidu.aop.banauto.MyAspect">bean>

   

    <bean id="proxyServiceId" class="org.springframework.aop.framework.ProxyFactoryBean">

       <property name="interfaces" value="com.baidu.aop.banauto.UserService">property>

       <property name="target" ref="userServiceId">property>

       <property name="interceptorNames" value="myAspectId">property> 

    bean>

beans>

 

  • 测试

测试类:

public class Demo {

    @Test

    public void test(){

       String xmlPath = "com/baidu/aop/banauto/applicationContext.xml";

      

       ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);

      

       UserService userService = (UserService) applicationContext.getBean("proxyServiceId");

      

       userService.addUser();

      

       userService.remvoeUser();

    }

}

  • 测试结果

AOP详解_第2张图片

 

  • AOP自动装配
  • 准备

添加jar包,加入Aspect表达式的jar包(依赖包下),见下图:

AOP详解_第3张图片

 

  • 编程

实现与上一节一致

  • 配置

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-4.0.xsd

                     http://www.springframework.org/schema/aop

                      http://www.springframework.org/schema/aop/spring-aop.xsd">

 

   

    <bean id="userServiceId" class="com.baidu.aop.auto.UserServiceImpl">bean>

   

    <bean id="myAspectId" class="com.baidu.aop.auto.MyAspect">bean>

   

    <aop:config> 

       <aop:pointcut expression="execution(* com.baidu.aop.auto.*.*(..))" id="myPointCutId"/>

       <aop:advisor advice-ref="myAspectId" pointcut-ref="myPointCutId"/>    

    aop:config>

beans>

 

 

  • 测试

测试类:

AOP详解_第4张图片

测试结果:

AOP详解_第5张图片

 

你可能感兴趣的:(Spring)