springAOP原理以及概念

需求:
1、拦截所有业务方法
2、判断用户是否有权限,有权限就让他执行业务方法,没有权限就不允许执行。(是否有权限是根据user是否为null作为判断依据)

思考:

我们该如何实现?

思路1:

  我们在每个业务方法上面加上判断语句。

否决掉了。代码过多,不灵活如果我需要更改需求就要挂掉。

解决方式:

使用动态代理实现。

Proxy动态代理。要求:被代理的对象需要有父接口。

准备代码:

package cn.itcast.service;

public interface PersonService {
    public abstract String getPersonName(Integer personId);
    public abstract void save(String name);
    public abstract void update(String name,Integer personId);
}

package cn.itcast.service.impl;

import cn.itcast.service.PersonService;

public class PersonServiceBean implements PersonService{
    private String user=null;
    
    public PersonServiceBean(){}
    
    public String getUser() {
        return user;
    }

    public PersonServiceBean(String user){
        this.user=user;
    }
    
    
    public String getPersonName(Integer personId) {
        System.out.println("我是getPersonName()方法");
        return "xxx";
    }

    
    public void save(String name) {
        System.out.println("我是save()方法");
    }

    
    public void update(String name, Integer personId) {
        System.out.println("我是update()方法");
    }

}
View Code

Proxy代理:

package cn.itcast.aop;

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

import cn.itcast.service.impl.PersonServiceBean;

public class JDKProxyFactory implements InvocationHandler{
    private Object targetObject;
    
    public Object createProxyInstance(Object targetObject){
        this.targetObject=targetObject;
        return     Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(), 
                this.targetObject.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {//环绕通知
        PersonServiceBean bean=(PersonServiceBean) targetObject;
        Object result=null;
        if(bean!=null && bean.getUser()!=null){
            try{
                //...advice()-->前置通知
                result=method.invoke(targetObject, args);
                //...afteradvice()-->后置通知
            }catch(RuntimeException e){
                //exceptionadvice()-->例外通知
            }finally{
                //finallyadvice()-->最终通知
            }
            
        }
        return result;
    }
}

如果操作的目标对象没有父接口,应该怎么做呢?

使用cglib.jar生成代理对象

原理:

生成的代理对象继承自原对象,重写了原对象的除了final外方法

导入jar:

cglib-nodep-2.1_3.jar

主要代码:

package cn.itcast.aop;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import cn.itcast.service.impl.PersonServiceBean;

public class CGlibProxyFactory implements MethodInterceptor{
    private Object targetObject;
    
    public Object createProxyInstance(Object targetObject){
        this.targetObject=targetObject;
        Enhancer enhancer=new Enhancer();
        enhancer.setSuperclass(this.targetObject.getClass());//继承了目标类,对目标类里面所有非final方法进行和覆盖,在覆盖的方法内添加自身代码
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args,
            MethodProxy methodProxy) throws Throwable {
        PersonServiceBean bean=(PersonServiceBean) targetObject;
        Object result=null;
        if(bean!=null && bean.getUser()!=null){
            result=method.invoke(targetObject, args);
        }
        return result;
    }
}

spring的AOP操作的内部原理就是使用的上面两种动态代理方式。

现在讲讲AOP的一些概念:

横切性关注点

前面我们思考的拦截对象拦截方式等叫做横切性关注点。
对什么进行拦截,拦截后应该做什么,这些思考的步骤,我们可以定义为横切性关注点。

aspect(切面):
指横切性关注点的抽象即为切面,它与类相似,只是两者的关注点不一样,类时对物体特征的抽象,而切面是横切性关注点的抽象。

joinpoint(连接点)
所谓连接点,就是指那些被拦截到的方法。在上面的例子中,练接点是绝大部分方法(非native),在spring中,这些点指的是方法,因为spring只支持方法类型的连接点,实际上joinpoint还可以是field或者类构造器

pointcut(切入点):
所谓切入点,就是指的我们需要拦截的连接点的定义,在上面的例子中指的是业务方法

advice(通知):拦截到连接点之后需要做的事

 

public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {//环绕通知
        PersonServiceBean bean=(PersonServiceBean) targetObject;
        Object result=null;
        if(bean!=null && bean.getUser()!=null){
            try{
                //...advice()-->前置通知
                result=method.invoke(targetObject, args);
                //...afteradvice()-->后置通知
            }catch(RuntimeException e){
                //exceptionadvice()-->例外通知
            }finally{
                //finallyadvice()-->最终通知
            }
            
        }
        return result;
    }

target(目标对象):

代理的目标对象

weave(织入):
将aspects应用到target对象并导致proxy对象创建的过程称为织入

introduction(引入):
在不修改类代码的前提下,Introduction可以在运行期为类动态地添加一些方法或者Field

原文地址:https://www.cnblogs.com/aigeileshei/p/5913122.html