AOP的概念

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAeG1oLXN4aC0xMzE0,size_20,color_FFFFFF,t_70,g_se,x_16优点:解耦

 

利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

主要功能

日志记录,性能统计,安全控制,事务处理,异常处理等等。

主要意图

将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。

 

AOP相关概念

1.方面(Aspect)

2.连接点(Joinpoint)

3.通知(Advice): 各种类型的通知包括“around”、“before”和“throws”通知。

许多AOP框架包括Spring都是以拦截器做通知模型,维护一个“围绕”连接点的拦截器链。

Spring中定义了四个advice:

BeforeAdvice, AfterAdvice, ThrowAdvice和DynamicIntroductionAdvice

4.切入点(Pointcut)

5.引入(Introduction): 添加方法或字段到被通知的类。

6.目标对象(Target Object): 被通知或被代理对象。

7.AOP代理(AOP Proxy): AOP框架创建的对象,包含通知。

8.织入(Weaving): 组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。

 

实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。

在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。

 

Spring AOP代理对象的生成

Spring提供了两种方式来生成代理对象: JDKProxy和Cglib,具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。默认的策略是如果目标类是接口,则使用JDK动态代理技术,否则使用Cglib来生成代理。

 

静态代理

JDK动态代理

CGlib动态代理

静态代理

静态代理很简单,咱们自己在写代码的时候都会写到这种类似静态代理的代码。简单来说,就是把被代理类作为参数传给代理类的构造方法,让代理类替被代理类实现更强大的功能。

 

public class StaticProxyTest { 

      public static void main(String[] args) {

            UserService userService = new UserService();

            LogProxy logProxy = new LogProxy(userService);

            logProxy.addUser();

            logProxy.deleteUser();

      }

}

 

interface IUserService{

      void addUser();

      void deleteUser();

}

 

class UserService implements IUserService{

      @Override

      public void addUser() {

            System.out.println("添加用户");

        }

        @Override    

        public void deleteUser() {

            System.out.println("删除用户");

        }

}

 

//日志代理

class LogProxy implements IUserService{    

    //目标类    

    private UserService target;

 

    public LogProxy(UserService target){

          this.target = target;

      }

  

      @Override    

      public void addUser() {

          System.out.println("记录日志开始");

          target.addUser();

          System.out.println("记录日志结束");

      }

  

      @Override

      public void deleteUser() {

          System.out.println("记录日志开始");

          target.deleteUser();

          System.out.println("记录日志结束");

      }

}

动态代理在Spring源码中,用到的动态代理主要有两种,JDK动态代理以及CGLib动态代理。

两者主要区别是:

JDK动态代理一般针对实现了接口的类生成代理。

目标对象没有实现接口,则默认会采用CGLIB代理。如果目标对象实现了接口,可以强制使用CGLIB实现代理。

 

相同点:两种动态代理本质上都是字节码组装

 

如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理。所有该目标对象实现的接口都将被代理。 若该目标对象没有实现任何接口,则创建一个CGLIB代理。

CGLIB代理模式下每一个目标对象创建一个子类。每一个代理实例会生成两个对象:实际代理对象和它的一个实现了通知的子类实例。

且CGLib的效率没有使用JDK代理机制高,速度平均要慢8倍左右。

 

JDK动态代理的代理类一般需要实现接口

public class JdkProxyTest {

    public static void main(String[] args) {

        IPersonService personService = JdkDynamicProxy.getProxy();

        personService.addPerson();

        personService.deletePerson();

    }

}

 

interface IPersonService{

    void addPerson();

    void deletePerson();

}

 

class PersonService implements IPersonService{

    @Override   

    public void addPerson() {

        System.out.println("添加人物");

    }

    @Override

    public void deletePerson() {

        System.out.println("删除人物");

    }

}

 

/**

 * newProxyInstance方法参数说明:

 * ClassLoader loader:指定当前目标对象使用的类加载器,获取加载器的方法是固定的

 * Class<?>[] interfaces:指定目标对象实现的接口的类型,使用泛型方式确认类型

* InvocationHandler:指定动态处理器,执行目标对象的方法时,会触发事件处理器的方法

 */

class JdkDynamicProxy{

    public static IPersonService getProxy(){

 

        IPersonService personService = new PersonService();

 

        IPersonService proxy = (IPersonService) Proxy.newProxyInstance(IPersonService.class.getClassLoader(), new Class<?>[]{IPersonService.class}, new InvocationHandler() {

            @Override

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

               System.out.println("记录日志开始");

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

               System.out.println("记录日志结束");

              return obj;

          }

      });

       return proxy;

    }

}

CGLib动态代理

public class CglibProxyTest {

    public static void main(String[] args) {

        CglibProxy proxy = new CglibProxy();

        Train t = (Train)proxy.getProxy(Train.class);

        t.move();

    }

}

 

class Train {

    public void move(){

        System.out.println("火车行驶中...");

    }

}

 

class CglibProxy implements MethodInterceptor {

 

    private Enhancer enhancer = new Enhancer();

 

    public Object getProxy(Class clazz){

        enhancer.setSuperclass(clazz);

        enhancer.setCallback(this);

        return enhancer.create();

    }

 

    /**

     * 拦截所有目标类方法的调用

     * obj 目标类的实例

     * m 目标方法的反射对象

     * args 方法的参数

     * proxy代理类的实例

     */

    @Override

    public Object intercept(Object obj, Method m, Object[] args, MethodProxy proxy) throws Throwable {

        System.out.println("日志开始...");

        //代理类调用父类的方法

        proxy.invokeSuper(obj, args);

        System.out.println("日志结束...");

        return null;

    }

}

原理分析

下面我们来研究一下Spring如何使用JDK来生成代理对象,具体的生成代码放在JdkDynamicAopProxy这个类中,假设我们要对下面这个用户管理进行代理:

 

public interface UserMgr {  

    void addUser();  

    void de

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值