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联盟实现包

 

  • 编程

目标类接口 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>

    <!-- 配置代理类

       interfaces: 目标类的接口们  类型 string

       target: 目标类 类型object 因此用 ref

       interceptorNames : 增强类(切面类) ,类型string[] 如果设置一个值用value ,否则用 <array></array>

     -->

    <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自动装配
  • 准备

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

 

  • 编程

实现与上一节一致

  • 配置

<?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="" id=""/> 确定切入点和增强点构成切面 expression:切入点表达式(确定切入点)

       id :别名,方便引用

       <aop:advisor advice-ref="增强类的id" pointcut-ref="上面的别名"/>

     -->

    <aop:config> 

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

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

    </aop:config>

</beans>

 

 

  • 测试

测试类:

测试结果:

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring AOP(面向切面编程)是Spring框架中的一个模块,用于提供横切关注点(Cross-Cutting Concerns)的支持。横切关注点是与应用程序的核心业务逻辑无关的功能,例如日志记录、性能统计、事务管理等。 在Spring AOP中,通过定义切面(Aspect)来捕获横切关注点,并将其应用到目标对象的方法中。切面由切点(Pointcut)和通知(Advice)组成。切点定义了在何处应用通知,通知则定义了在切点处执行的操作。 Spring AOP支持以下几种类型的通知: 1. 前置通知(Before Advice):在目标方法执行之前执行的通知。 2. 后置通知(After Advice):在目标方法执行之后执行的通知,不管方法是否抛出异常。 3. 返回通知(After Returning Advice):在目标方法成功执行并返回结果后执行的通知。 4. 异常通知(After Throwing Advice):在目标方法抛出异常后执行的通知。 5. 环绕通知(Around Advice):围绕目标方法执行的通知,可以在方法调用前后执行自定义操作。 除了通知,Spring AOP还支持引入(Introduction)和切点表达式(Pointcut Expression)等功能。引入允许为目标对象添加新的接口和实现,而切点表达式则允许开发人员定义切点的匹配规则。 要在Spring应用程序中使用AOP,需要进行以下步骤: 1. 引入Spring AOP的依赖。 2. 配置AOP代理。 3. 定义切面和通知。 4. 配置切点和通知之间的关系。 总之,Spring AOP提供了一种便捷的方式来处理横切关注点,使得开发人员可以将关注点与核心业务逻辑分离,提高代码的可维护性和可重用性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值