springAOP面向切面编程

AOP中文手册没法看,概念比佛法还深还抽象!我们进入例子理解

前提铺垫:动态代理模式

 

 

Spring容器的启动流程

1)容器创建容器中的对象

2)进入装配阶段

3)调用init()方法

4)getBean得到对象调用方法

5)容器关闭调用destroy

 

 

静态代理模式

public class PersonProxy implements PersonDao{
  private Person dao;
  private Transaction tran;
  
  public Personproxy(Person dao,Transaction tran){
    this.dao=dao;
    this.tran=tran;
  }
  
  @Override
   public void savePerson(){
      tran.beginTransaction();
      dao.savePerson();
      tran.commit()
   } 

}

 

看起来好香很像装饰模式哦。

首先PersonDao是一个接口定义了savePerson();实际使用的时候我们给他开事物非常麻烦,于是我是用一个代理类来得到他的代理

然后重写的时候添加事物。总结一下:

1静态代理没有做到代码的重用,无法切面编程。如果接口定义了xxx()那么你得事务还得在xxx()中体现

2如果你的service层中有一百个类,难道用静态代理写100个代理类?接口中国100个方法你就要在代理中写100个?

  那还不如直接在接口中写事务算了,何必重新写代理。

3因为代理类也继承了被代理类的接口,一旦接口发生改变那么代理类的改变也不堪设想。

 

因此静态代理类无法解决复杂的问题以及不可能处理面向切面编程。

 

那么我想需要使用代理解决什么问题呢?

用一个代理类实现所有dao层或者service层的方法的事物的开启和提交,一次编写,横切一个层。只能使用动态代理

 

JDK动态代理

动态代理分为JDK的方式和Cglib的方式

企业里就算不用springAOP也不会用JDKProxy

1、在拦截器中只能处理目标对象的目标方法功能单一。如果累加就会臃肿。本例只能处理事物

2、有20service每个类有20个方法,百分之50需要开启事物,200个方法需要事物

200个方法的方法名都不一样,你得代理如何判断方法呢?(可以用打注解来解决)

但是也要打200个注解,也还是麻烦。

所以拦截器中的invoke方法的if判断在真实开发环境下是不靠谱的。因为方法很多。打注解不是完美解决方法

public class MyHandler implements InvocationHandler{

  private Object target;//目标类

  private Transaction transaction;

  public MyHandler(Object target, Transaction transaction) {

    super();

    this.target = target;

    this.transaction = transaction;

  }

  @Override

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

    // TODO Auto-generated method stub

    String metnodname=method.getName();

    if("savePerson".equals(metnodname)||"updatePerson".equals(metnodname)){

      this.transaction.beginTransaction();

      method.invoke(target, args);

     this.transaction.commit();

    }else{

      method.invoke(target, args);

    }

    return null;

  }

}

/**

 * 1、invoke方法什么时候执行

 * 当调用代理对象的方法的时候,进入自己定义的handler的invoke

 * 2、代理对象的方法体的内容是什么

 * invoke方法中的内容就是代理对象的方法内容

 * 拦截器中的invoke方法中的参数method是谁在什么时候传递过来的?

 * 代理对象调用方法的时候,进入了拦截器中的invoke方法,所以invoke方法中的参数method就是

 *       代理对象调用的方法

 * @param args

 */

public static void main(String[] args) {

    Object target=new PersonDaoImpl();

    Transaction t=new Transaction();

    MyHandler interceptor = new MyHandler(target, t);

    PersonDao proxy=    (PersonDao)Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),interceptor);

    proxy.savePerson();

    proxy.updatePerson();

  }

}

自定义拦截器(其实就是把功能抽象理解为拦截器的功能,把这些功能放入一个自定义叫做拦截器的类中),把事物啊 日志啊等等需要在代理中添加的功能都放入拦截器中,这样就可以在代理对象的方法调用的时候将拦截器全部执行。只是理解为拦截器,其实就是一个功能集合(参考代码)

 

 

Cglib代理(重中之重)

Cglibspring中帮我们提供了

Cglib-nodep-2.1.3.jar导入工程

通过他产生的代理对象是目标类的子类

就是说代理类不必和被代理类实现同一个接口,因为代理类就是被代理类孩子

public class MyInterceptor implements MethodInterceptor{
    private Object target;//目标类
    private Transaction transaction;
    
    public MyInterceptor(Object target, Transaction transaction) {
        super();
        this.target = target;
        this.transaction = transaction;
    }

    public Object createProxy(){
        //代码增强类
        Enhancer enhancer = new Enhancer();
        enhancer.setCallback(this);//参数为拦截器(设置回调者)
        enhancer.setSuperclass(target.getClass());//生成的代理类的父类是目标类
        return enhancer.create();
    }
    @Override
    public Object intercept(Object arg0, Method method, Object[] arg2, MethodProxy arg3) throws Throwable {
        this.transaction.beginTransaction();
        method.invoke(target);
        this.transaction.commit();
        return null;
    }

}

============================

public class Client {
    @Test
    public void testCGlib(){
        Object target = new PersonDaoImpl();
        Transaction transaction = new Transaction();
        MyInterceptor interceptor = new MyInterceptor(target, transaction);
        PersonDaoImpl personDaoImpl = (PersonDaoImpl)interceptor.createProxy();
        personDaoImpl.savePerson();
    }
}

AOP的各个概念

spring中已经帮我们做好了AOP,只需要了解概念即可。

之前我们看的Transactioin类就是一个切面

暂时可以理解为修饰service层功能的类就是切面,切面的方法就是通知

public clss Transaction{      //切面

  public void beginTransaction(){

    。。。。。。。

  }

  public void commit(){    //通知

    ..................

  }

}

 

personDao.updatePerson()

客户端调用哪个方法,那个方法就是连接点

 

之前的invoke方法中的判断代码:

if("savePerson".equals(metnodname)||"updatePerson".equals(metnodname)){

      this.transaction.beginTransaction();

      method.invoke(target, args);

     this.transaction.commit();

}else{

   method.invoke(target, args);

}

 

整个判断的过程就是切入点(相当于条件)

整个形成代理对象的方法过程就称为织入。

 

excution表达式图---

----

----

---

好好研究下表达式的写法。

原理:

 

 

 

通知的分类-------------------------------------------

 

posted @ 2017-04-09 20:34  码大爷  阅读(137)  评论(0编辑  收藏  举报