约定编程:我们只需要实现约定的流程部分,而具体实现通过框架实现
“约定编程”(Convention Over Configuration)是一种软件开发的理念,旨在减少开发者在项目配置上的决策,并通过约定促进开发者之间的协作和项目的一致性。
aop的约定执行流程:
AOP的具体实现过程(由框架实现)
有三个重要的对象,一个是被代理的类,一个是拦截器,一个是代理对象。
public interface HelloService{
public void sayHello(String name);
}
//被代理对象
public class HelloServiceImpl implements HelloService{
@Override
public void sayHello(String name){
System.out.println("hello"+name);
}
}
//拦截器接口
public interface Interceptor{
public boolean before();
public void after();
public Object around(Invocation invocation);
public void afterReturning();
public void afterThrowing();
boolean useAround();
}
执行被代理对象的方法的一个包装类
public class Invocation{
private Object[] params;
private Method method;
private Object target;
public Invocation(Object target,Method method,Object[] params){
this.target=target;
this.method=method;
this.params=params;
}
public Object proceed(){
return method.invoke(target,params);
}
}
//拦截器的实现
public class MyInterceptor implements Interceptor{
@Override
public boolean before(){;}
@Override
public boolean useAround(){ return true;}
@Override
public void after(){;}
@Override
public void after(){;}
@Override
public Object around(Invocation invocation){
System.out.println("around before...");
Object obj=invocation.proceed();
System.out.println("around after...");
return obj;
}
@Override
public void afterReturning(){;}
@Override
public void afterThrowing(){;}
}
//实现aop约定编程的具体类
public class ProxyBean implements InvocationHandler{
private Object target=null;//被代理对象
private Interceptor interceptor=null;//拦截器
@Override
public static Object getProxyBean(Object target,Interceptor interceptor){
ProxyBean proxyBean = new ProxyBean();
proxyBean.target = target;
proxyBean.interceptor = interceptor;
Object proxy=Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces().proxyBean);
return proxy;//返回代理对象
}
@Override
public Object invoke(Object proxy,Method method,Object[] args){
boolean exceptionFlag = false;
Invocation invocation = new Invocation(target,method,args);
this.interceptor.before();
Object retObj = null;
if(this.interceptor.useAround()){
retObj=this.interceptor.around(invocation);
else
retObj=method.invoke(target,args);
return retObj;
}
AOP
切点(Pointcut)在 AOP 中用于定义哪些连接点(Join Point)会被拦截器(Advice)所拦截。连接点是在程序执行过程中能够插入拦截器的点,比如方法调用、方法执行时异常抛出等。切点定义了一组连接点,这些连接点满足切点的条件,会被相应的拦截器所拦截。
所以,切点可以看作是一种匹配规则,它确定了哪些连接点会被织入(Weaving)到切面(Aspect)中。连接点是一个程序执行的具体位置,而切点则定义了应该在哪些具体位置执行拦截器中的逻辑。
切面(Aspect)
在 Spring 框架中,切面通常作为一个普通的 Java 类,并使用 @Aspect 注解进行标注。
在切面中,你可以定义一系列的通知(Advice)以及切点(Pointcut)。
通知(Advice)
通知是切面的具体行为。它定义了在程序执行的不同点上执行的代码。
Spring AOP 支持以下几种类型的通知:
前置通知(Before advice):在方法执行前执行。
后置通知(After returning advice):在方法执行后执行。
后置异常通知(After throwing advice):在方法抛出异常时执行。
后置最终通知(After finally advice):在方法执行后执行,无论方法是否抛出异常都会执行。
环绕通知(Around advice):在方法执行前后都执行,并且可以控制方法的执行。
切点(Pointcut):一个切面匹配的所有连接点都叫切点。
切点的主要功能就是简化连接点的定义和书写。
定义切点后,连接点想要织入切面,就将这个切面的连接点设置为切点,简化了开发。
可以只使用连接点而不使用切点。
切点定义了切面逻辑将被应用到哪些连接点(join points)上。
通过使用切点表达式(Pointcut expressions),可以精确地指定哪些方法、哪些类需要应用切面逻辑。
连接点(Join point)
连接点是在应用程序执行过程中可以插入切面的点,方法调用或异常抛出时。
引入(Introduction)
引入允许向现有类添加新方法或属性。在 Spring AOP 中,引入允许你向现有的类中添加新的接口实现。
目标对象(Target object)
目标对象是被代理的对象,它包含了切面逻辑所要应用的方法。
代理(Proxy)
代理是一个类,它包装了目标对象,并且可以截获对目标对象方法的调用,以便在调用前后执行切面逻辑。
织入(Weaving)
织入是将切面逻辑应用到目标对象的过程。织入可以在编译时、类加载时、运行时进行。
为什么要使用AOP?
减少重复工作,比如使用jdbc需要获得连接和statement,使用AOP可以简化这些过程。
定义切面
@Aspect
public class MyAspect{
@Before("execution(*com.springboot.chapter4.aspect.service.impl.UserServiceImp.printUser(..))")//通过连接点接入
public void befor(){}
@After("execution(*com.springboot.chapter4.aspect.service.impl.UserServiceImp.printUser(..))")
public void after(){}
@AfterReturning("execution(*com.springboot.chapter4.aspect.service.impl.UserServiceImp.printUser(..))")
public void returning(){}
@AfterThrowing("execution(*com.springboot.chapter4.aspect.service.impl.UserServiceImp.printUser(..))")
public void throwing(){}
}
定义切点
会使用excution()里的正则式去匹配使用切点的,为了简化开发,我们也可以在切面中定义一个切点,然后赋值给方法。
@Aspect
public class MyAspect{
@Pointcut("execution(*com.springboot.chapter4.aspect.esrvice.impl.UserServiceImple.printUesr(..))")
public void pointCut(){}
@Before("pointCut()")//使用切点(定义了切点的方法名)作为通知的连接点
public void before(){}
@After("ponintCut()")
public void after(){}
}
环绕通知
最强大的切面,不执行原方法,而是执行环绕通知的方法。
@Around("pointCut()")
public void around(ProceedingJoinPoint jp){
System.out.println("around before..");
jp.proceed();
System.out.println("after..");
}
execution中的正则表达式
execution(*com.springboot.chapter4.aspect.service.impl.UserServiceImpl.printUser(…))
*表示返回类型,(…)表示可以进行任意参数匹配