zoukankan      html  css  js  c++  java
  • Spring AOP 原理的理解

      >AOP基本概念

      1)通知(Advice):织入到目标类连接点上的一段程序代码。通知分为五种类型:

      - Before:在方法被调用之前调用

      - After:在方法完成后调用通知,无论方法是否执行成功

      - After-returning:在方法成功执行之后调用通知

      - After-throwing:在方法抛出异常后调用通知

      - Around:通知了好、包含了被通知的方法,在被通知的方法调用之前后调用之后执行自定义的行为

      2)切点(Pointcut):AOP通过“切点”定位特定的连接点

      3)连接点(Joinpoint):程序执行的某个特定位置:如类开始初始化前、类初始化后、类某个方法调用前、调用后、方法抛出异常后。这些代码中的特定点,称为“连接点”。

      4) 织入(Weaving):织入是将增强添加到目标类具体连接点上的过程。AOP有三种织入方式:

      - 编译期织入,这要求使用特殊的Java编译器;

      - 类装载期织入,这要求使用特殊的类装载器;

      - 动态代理织入,在运行期为目标类添加增强生成子类的方式。

      Spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。

      5)切面(Aspect)切面由切点和通知组成,它既包括了横切逻辑的定义,也包括了连接点的定义

      Spring 是切片流程

      代理模式

      就好比明星和经纪人,经纪人负责接活,负责明星唱歌前会场准备,明星唱歌后收钱。 代理类其实就是在代理对象,前后做了一些其他的处理, 这已经具备 AOP的轮廓了

      静态代理模式栗子

      // 接口

      public interface IUserDao {

      void save();

      void find();

      }

      // 目标对象

      public class UserDao implements IUserDao {

      @Override

      public void save() {

      System.out.println("模拟:保存用户!");

      }

      @Override

      public void find() {

      System.out.println("模拟:查询用户");

      }

      }

      /**

      * 静态代理 特点:

      * 1. 目标对象必须要实现接口

      * 2. 代理对象,要实现与目标对象一样的接口

      */

      public class UserDaoProxy implements IUserDao {

      // 代理对象,需要维护一个目标对象

      private IUserDao target = new UserDao();

      @Override

      public void save() {

      System.out.println("代理操作: 开启事务...");

      target.save(); // 执行目标对象的方法

      System.out.println("代理操作:提交事务...");

      }

      @Override

      public void find() {

      target.find();

      }

      }

      public class StaticProxyTest {

      /**

      * @param args

      */

      public static void main(String[] args) {

      IUserDao proxy = new UserDaoProxy();

      proxy.save();

      }

      }

      可以看到,静态代理是必须要有接口的,代理类和目标类都得事先接口,这样就显得很麻烦了,每次代理一个目标对象,就得做一个代理类,有没有一种方式,可以使用一个代理 ,代理多个目标对象呢?

      动态代理模式栗子

      动态代理不需要提前建立代理,而是在运行时,为目标对象动态生成代理类

      // 接口

      public interface IUserDao {

      void save();

      void find();

      }

      // 目标对象

      public class UserDao implements IUserDao {

      @Override

      public void save() {

      System.out.println("模拟: 保存用户!");

      }

      @Override

      public void find() {

      System.out.println("查询");

      }

      }

      /**

      * 动态代理:JDK 动态代理采用的是反射机制实现

      * 代理工厂,给多个目标对象生成代理对象!

      *

      */

      public class ProxyFactory {

      // 接收一个目标对象

      private Object target;

      public ProxyFactory(Object target) {

      this.target = target;

      }

      // 返回对目标对象(target)代理后的对象(proxy)

      public Object getProxyInstance() {

      Object proxy = Proxy.newProxyInstance(

      target.getClass().getClassLoader(), // 目标对象使用的类加载器

      target.getClass().getInterfaces(), // 目标对象实现的所有接口

      new InvocationHandler() { // 执行代理对象方法时候触发

      @Override

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

      throws Throwable {

      // 获取当前执行的方法的方法名

      String methodName = method.getName();

      // 方法返回值

      Object result = null;

      if ("find".equals(methodName)) {

      // 直接调用目标对象方法

      result = method.invoke(target, args);

      } else {

      System.out.println("开启事务...");

      // 执行目标对象方法

      result = method.invoke(target, args);

      System.out.println("提交事务...");

      }

      return result;

      }

      }

      );

      return proxy;

      }

      }

      public class JDKDynamicProxyTest {

      /**

      * @param args

      */

      public static void main(String[] args) {

      // 目标对象

      IUserDao target = new UserDao();

      // 创建代理类

      IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();

      System.out.println("代理对象: "+proxy.getClass());

      proxy.save();

      }

      }

      静态代理动态代理总结

      可以总结一下,JDK 动态代理

      // 创建代理类

      IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();

      实际上 隐藏了动态的去实现 目标对象的一个接口

      class $jdkProxy implements IUserDao{}

      也就是说 使用JDK 反射方式实现动态代理,目标对象必须实现一个接口,这就可能出现问题了,假设一个类,就是没有实现接口怎么办?

      CGLIB实现动态代理实现栗子

      CGLIB是使用继承的方式动态生成代理类,这个代理类是继承目标类的,这个就有个问题,需要目标类不被final修饰。

      有点类似

      public class UserDao{}

      // CGLIB 是以动态生成的子类继承目标的方式实现,程序执行时,隐藏了下面的过程

      public class $Cglib_Proxy_class extends UserDao{}

      CGLIB实现

      // 目标对象

      public class UserDao {

      public void save() {

      System.out.println("模拟: 保存用户!");

      }

      public void find() {

      System.out.println("查询");

      }

      }

      public class CGLIBProxyFactory {

      static class SimpleInterceptor implements MethodInterceptor {

      /**

      * @see org.springframework.cglib.proxy.MethodInterceptor#intercept(java.lang.Object,

      * java.lang.reflect.Method, java.lang.Object[],

      * org.springframework.cglib.proxy.MethodProxy)

      */

      @Override

      public Object intercept(Object target, Method methmod, Object[] args, MethodProxy proxy) throws Throwable {

      System.out.println("entering " + methmod.getName());

      Object result = proxy.invokeSuper(target, args);

      System.out.println("leveaing " + methmod.getName());

      return result;

      }

      }

      public static T getProxy(Class cls) {

      Enhancer enhancer = new Enhancer();

      // 继承目标类

      enhancer.setSuperclass(cls);

      enhancer.setCallback(new SimpleInterceptor());

      return (T) enhancer.create();

      }

      }

      public class CGLIBProxyTest {

      public static void main(String[] args) {

      //生成代理 没有接口

      UserDao proxy = (UserDao) CGLIBProxyFactory.getProxy(UserDao.class);

      System.out.println("代理类:"+ proxy.getClass());

      proxy.save();

      }

      }无锡正规妇科医院 http://www.jlfukeyy.com/

      JDK和CGLIB的区别

      1.上面可以可以看到 CGLIB是不需要 目标对象实现接口的, CGLIB是通过继承来实现的

      2. JDK动态代理是需要一个具体的目标对象的,但是CGLIB是不需要这么一个具体对象的

      Spring AOP 是怎样实现的呢?

      1.AOP 是基于动态代理模式

      2.AOP是方法级别的

      3.AOP可以分类业务代码和关注点代码(日志,事务等)

      AOP 是什么时候生成代理的?

      AOP 代理主要分为静态代理和动态代理两大类,静态代理以 AspectJ 为代表;而动态代理则以 Spring AOP 为代表

      IOC容器BeanDefinitionMap里面结构看内容是啥

      bean: class [org.springframework.aop.aspectj.AspectJPointcutAdvisor];

      scope=;

      abstract=false;

      lazyInit=false;

      autowireMode=0;

      dependencyCheck=0;

      autowireCandidate=true;

      primary=false;

      factoryBeanName=null;

      factoryMethodName=null;

      initMethodName=null;

      destroyMethodName=null,

      org.springframework.aop.aspectj.AspectJPointcutAdvisor#2=Root

      bean: class [org.springframework.aop.aspectj.AspectJPointcutAdvisor];

      scope=;

      abstract=false;

      lazyInit=false;

      autowireMode=0;

      dependencyCheck=0;

      autowireCandidate=true;

      primary=false;

      factoryBeanName=null;

      factoryMethodName=null;

      initMethodName=null;

      destroyMethodName=null,

      org.springframework.aop.aspectj.AspectJPointcutAdvisor#3=Root

      bean:class [org.springframework.aop.aspectj.AspectJPointcutAdvisor];

      scope=;

      abstract=false;

      lazyInit=false;

      autowireMode=0;

      dependencyCheck=0;

      autowireCandidate=true;

      primary=false;

      factoryBeanName=null;

      factoryMethodName=null;

      initMethodName=null;

      destroyMethodName=null,

      org.springframework.aop.aspectj.AspectJPointcutAdvisor#0=Root

  • 相关阅读:
    Drupal Coder 模块远程命令执行分析(SA-CONTRIB-2016-039)
    Python 实现 ZoomEye API SDK
    程序员互动联盟第一届编码大赛第二题解题分享
    python中各进制之间的转换
    记一次ctf比赛解密题的解决(可逆加密基本破解之暴力破解)
    使用JsonConfig控制JSON lib序列化
    openMRS项目
    Harmonic Number(调和级数+欧拉常数)
    Pairs Forming LCM(素因子分解)
    Uva 11395 Sigma Function (因子和)
  • 原文地址:https://www.cnblogs.com/djw12333/p/11356717.html
Copyright © 2011-2022 走看看