springAOP原理以及概念

2023-06-25,,

需求:
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()方法");
} }

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

springAOP原理以及概念的相关教程结束。

《springAOP原理以及概念.doc》

下载本文的Word格式文档,以方便收藏与打印。