美文网首页
Spring AOP

Spring AOP

作者: 磊_5d71 | 来源:发表于2018-10-19 17:17 被阅读0次

AOP简介

  • AOP Aspect Oriented Programing 面向切面编程
  • AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(如性能监视、事务管理、安全检查、缓存等)
  • AOP横向抽取与传统纵向继承对比图


    图片.png
  • Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码。

AOP相关术语

  • Joinpoint(连接点):所谓的连接点是指那些被拦截到的点。在Spring中,这些点指的是方法,Spring只支持方法类型的连接点。
  • Pointcut(切入点):所谓的切入点是指我们要对哪些Joinpoint进行拦截的定义。
  • Advice(通知/增强):所谓通知是指拦截到Joinpoint之后要做的事情就是通知。通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)。
  • Introduction(引介):引介是一种特殊的通知,在不修改类代码的前提下,在运行期为类动态地添加一些方法或Field。
  • Target(目标对象):代理的目标对象
  • Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。Spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。
  • Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类。
  • Aspect(切面):是切入点和通知(引介)的结合。


    图片.png

AOP底层实现:JDk的动态代理

只能对实现了接口的类进行动态代理

  • UserDao接口
package com.alan.aop.demo1;

public interface UserDao {

    public void save();

    public void uodate();

    public void delete();

    public void find();
}
  • UserDaoImpl实现类
package com.alan.aop.demo1;

public class UserDaoImpl implements  UserDao {


    @Override
    public void save() {

        System.out.println("保存用户。。。");
    }

    @Override
    public void uodate() {
        System.out.println("修改用户。。。");
    }

    @Override
    public void delete() {
        System.out.println("删除用户。。。");

    }

    @Override
    public void find() {
        System.out.println("查询用户。。。");

    }
}
  • 代理类
package com.alan.aop.demo1;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * UserDao代理类
 */
public class MyJdkProxy implements InvocationHandler {

    private UserDao userDao;

    //通过构造方法传入要代理的类
    public MyJdkProxy(UserDao userDao){
        this.userDao = userDao;
    }

    //产生代理类(对实现接口类产生代理)
    public Object createProxy(){

        //需要传入三个参数:类的加载器、类实现的接口、InvocationHandler接口
        Object proxy = Proxy.newProxyInstance(userDao.getClass().getClassLoader(),userDao.getClass().getInterfaces(),this);
        return proxy;
    }

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

        if("save".equals(method.getName())){
            System.out.println("权限校验。。。");
            return method.invoke(userDao,args);
        }
        return method.invoke(userDao,args);
    }
}
  • 测试类
package com.alan.aop.demo1;

import org.junit.Test;

public class SpringDemo1 {

    @Test
    public void demo1(){

        UserDao userDao = new UserDaoImpl();


        //创建代理
        UserDao proxy = (UserDao) new MyJdkProxy(userDao).createProxy();

        proxy.save();
        proxy.uodate();
        proxy.delete();
        proxy.find();
    }
}

AOP的底层实现:CGLIB的动态代理

  • 对于不使用接口的业务类,无法使用JDK动态代理
  • CGLIB采用非常底层字节码技术,可以为一个类创建子类,解决无接口代理问题
  • 实体类
package com.alan.aop.demo2;

public class ProductDao {


   public void save() {

       System.out.println("保存用户。。。");
   }

   public void uodate() {
       System.out.println("修改用户。。。");
   }

   public void delete() {
       System.out.println("删除用户。。。");

   }

   public void find() {
       System.out.println("查询用户。。。");

   }
}
  • 代理类
package com.alan.aop.demo2;

import com.alan.aop.demo1.MyJdkProxy;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class MyCglibProxy implements MethodInterceptor {


    private ProductDao productDao;


    //构造方法传入ProductDao对象
    public MyCglibProxy(ProductDao productDao){
        this.productDao = productDao;
    }


    //创建方法生成代理
    public  Object createProxy(){
        //1、创建核心类
        Enhancer enhancer = new Enhancer();
        //2、设置父类
        enhancer.setSuperclass(productDao.getClass());
        //3、设置回调(this代表当前对象,对实现接口的调用)
        enhancer.setCallback(this);
        //4、生成代理
        Object proxy = enhancer.create();
        return proxy;
}

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

        if("save".equals(method.getName())){
            System.out.println("用户校验。。。。");
            return  methodProxy.invokeSuper(proxy,args);
        }

        //invokeSuper调用父类的方法
        return methodProxy.invokeSuper(proxy,args);
    }
}
  • 测试类
package com.alan.aop.demo2;

import org.junit.Test;

public class SpringDemo2 {



    @Test
    public void demo1(){

        ProductDao productDao = new ProductDao();

        ProductDao proxy = (ProductDao) new MyCglibProxy(productDao).createProxy();

        proxy.delete();
        proxy.find();
        proxy.save();
        proxy.uodate();
    }
}

Spring代理实现

图片.png
图片.png

Spring AOP增强类型

图片.png 图片.png

Spring AOP切面类型

图片.png
  • StudentDao接口类
package com.alan.aop.demo3;

public interface StudentDao {

    public void save();

    public void update();

    public void delete();

    public void find();
}
  • StudentDaoImpl接口实现类
package com.alan.aop.demo3;

public class StudentDaoImpl implements StudentDao {


    @Override
    public void save() {
        System.out.println("学生保存。。。");

    }

    @Override
    public void update() {
        System.out.println("学生修改。。。");

    }

    @Override
    public void delete() {
        System.out.println("学生保存。。。");

    }

    @Override
    public void find() {
        System.out.println("学生查询。。。");

    }
}
  • 测试类
package com.alan.aop.demo3;


import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resources;


//通过注解简化测试。不需要在代码中通过ApplicationContext对象进行xml配置了
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDemo3 {


    @Autowired
    @Qualifier("studentDaoProxy")
    private StudentDao studentDao;

    @Test
    public void demo1(){
        studentDao.delete();
        studentDao.find();
        studentDao.save();
        studentDao.update();
    }

}
  • xml配饰文件
    <!--前置通知类型===================-->
    <bean id="myBeforeAdvice" class="com.alan.aop.demo3.MyBeforeAdvice"></bean>
    <!--Spring AOP产生代理对象-->
    <bean id="studentDaoProxy"  class="org.springframework.aop.framework.ProxyFactoryBean">
        <!--配置目标类-->
        <property name="target" ref="studentDao"></property>
        <!--配置要实现的接口-->
        <property name="proxyInterfaces" value="com.alan.aop.demo3.StudentDao"></property>
        <!--配置增强类型,采用拦截的名称-->
        <property name="interceptorNames" value="myBeforeAdvice"></property>

    </bean>
  • MyBeforeAdvice增强实现类
package com.alan.aop.demo3;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class MyBeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("前置增强。。。。");
    }
}

Spring带有切入点的切面配置案例(demo5)

图片.png

自动代理创建(demo6)

图片.png

Spring的传统AOP的基于切面信息的自动代理

相关文章

网友评论

      本文标题:Spring AOP

      本文链接:https://www.haomeiwen.com/subject/styqzftx.html