Spring AOP底层原理

什么是AOP

  • AOP:Aspect Oriented Programing(面向切面编程)
  • 采用横向抽取机制,取代传统继承体系重复性代码(性能监视、事务管理、安全检查、缓存)即代理机制
  • 使用纯JAVA实现,不需要专门的编写过程和类加载器,在运行期通过代理方式向目标织入增强代码

AOP相关术语

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

JDK动态代理

========interface========
public interface UserDao {
    public void save();
    public void update();
    public void delete();
    public void find();
}
========UserDaoImpl========
public class UserDaoImpl implements UserDao {
    public void save() {
        System.out.println("保存用户...");
    }
    public void update() {
        System.out.println("修改用户...");
    }
    public void delete() {
        System.out.println("删除用户...");
    }
    public void find() {
        System.out.println("查询用户...");
    }
}
========MyJdkProxy========
public class MyJdkProxy implements InvocationHandler{
    private UserDao userDao;
    public MyJdkProxy(UserDao userDao){
        this.userDao = userDao;
    }
    public Object createProxy(){
        Object proxy = Proxy.newProxyInstance(userDao.getClass().getClassLoader(),userDao.getClass().getInterfaces(),this);
        return proxy;
    }
    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);
    }
========Test=========
@Test
public void demo1(){
    UserDao userDao = new UserDaoImpl();
    UserDao proxy = (UserDao)new MyJdkProxy(userDao).createProxy();
    proxy.save();
    proxy.update();
    proxy.delete();
    proxy.find();
}
}

CGLIB生成代理

  • 生成了一个类,来继承这个目标类
  • 对于不使用接口的业务类,无法使用JDK动态代理
  • CGlib采用非常底层字节码技术,可以为一个类动态的增加一些方法也可以生成一个类去继承这个类,解决无接口代理问题
========ProdectDao========
public class ProdectDao {
    public void save(){
        System.out.println("保存商品....");
    }
    public void update(){
        System.out.println("修改商品....");
    }
    public void find(){
        System.out.println("删除商品....");
    }
    public void delete(){
        System.out.println("查询商品....");
    }
}
========MyCglibPorxy========
public class MyCglibPorxy implements MethodInterceptor {
    private ProdectDao prodectDao;
        public MyCglibPorxy(ProdectDao prodectDao){
            this.prodectDao=prodectDao;
        }
        public Object createProxy(){
            //1.创建核心类
            Enhancer enhancer = new Enhancer();
            //2.设置父类
            enhancer.setSuperclass(prodectDao.getClass());
            //3.设置回调
            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);
        }
            return methodProxy.invokeSuper(proxy,args);
    }
}
========Test========
@Test
public void demo1(){
    ProdectDao prodectDao = new ProdectDao();
    ProdectDao porxy = (ProdectDao) new MyCglibPorxy(prodectDao).createProxy();
    porxy.save();
    porxy.find();
    porxy.update();
    porxy.delete();
}

总结

  • Spring在运行期,生成动态代理对象,不需要特殊的编译器
  • Spring AOP的底层就是通过JDK动态代理或CGLib动态代理技术 为目标Bean执行横向织入
    1.若目标对象实现了若干接口,spring使用JDK的动态代理
    2.若目标对象没有实现任何接口,spring使用CGLIB动态代理
  • 程序中应优先对接口创建代理,便于程序解耦维护
  • 标记为final的方法,不能被代理,因为无法进行覆盖
  • JDK动态代理,是针对接口生成子类,接口中方法不能使用final修饰
  • CGLib是针对目标类生产子类,因此类或方法不能使用final修饰
  • Spring支持方法连接点,不提供属性的连接点

你可能感兴趣的:(spring,java,原型模式)