Spring 框架之Spring AOP的认识(二)
通过上一篇的例子,我们转换到AOP的概念上去。
Spring AOP的基本概念
连接点(Joinpoint):具体的方法,执行AOP织入流程的方法,相当于目标对象的业务方法。
切面(Aspect):对应拦截器的概念,定义内容(主要是通知)依据约定织入流程,定义aop执行流程的各种内容。
织入(Weaving):生成代理对象,组织流程的过程。
通知(Advice):前置通知,环绕通知,事后通知,异常通知,返回通知。
(1)前置通知:连接点之前执行的通知
(2)事后通知:当连接点方法退出的时候执行的通知(不论是正常返回还是异常退出)
(3)返回通知:连接点方法正常执行完成返回的通知
(4)异常通知:连接点的方法发生异常执行的通知
(5)环绕通知:包围一个连接点的通知,可以取代原有的业务方法的通知,可以自定义实现,也可以不执行这个通知
切点(Pointcut):简化连接点的编写,通过他可以匹配对应的连接点。标识哪些方法需要实现AOP
目标对象(Target Object):被代理的对象,被通知的对象。
AOP代理(AOP Proxy):就是代理对象,在Spring中有两种代理:(1)JDK,必须实现接口InvocationHandler;(2)CGLIB,不需要实现接口。
引入(Introduction): 添加方法或字段到被通知的类。
对应上一讲(Spring 框架之Spring AOP的认识(一))的关系如下:
连接点:目标对象的业务方法----hava()
切面:类似于拦截器----DinnerInterceptor接口的所有方法,就是所谓的通知
通知:(1)前置通知:before()
(2)事后通知:after()
(3)返回通知:afterReturning()
(4)异常通知:afterThrowing()
织入:把切面和连接点组织起来,制定流程过程-----bind()跟invoke()
目标对象:target ------ DinnerInterceptorImpl interceptoy = new DinnerInterceptorImpl ();
AOP代理:动态代理----JDK代理 Proxy;DinnerService proxy = (DinnerService)DinnerProxy.bind(target,interceptoy);
这个时候再通过一个流程图来加深印象:
从对应关系和流程图来看,你是不是没有发现切点这个基本概念,好了,那我们就继续往下看。
综合AOP(切点)
首先,我们要知道,Spring AOP是拦截方法级别的AOP:拦截某些类的某些方法,
事实上,并不是所有的方法都要实现AOP,只有某些方法需要实现,那AOP是怎么识别那些方法需要实现AOP,而哪些方法不需要实现呢?这时候,那我们就要进入切点这个基本概念了。
切点(Pointcut):简化连接点的编写,通过他可以匹配对应的连接点。简单来说,就是通过关联表达式来匹配需要实现AOP的方法,可以理解为,标识,标记某些方法方法,然后这些方法就会实现AOP,而没有标识的方法就不需要实现AOP。下面我们上实例。
public interface DinnerService{
//吃饭
public void hava();
//增加一个方法:不吃饭
public void noHave();
}
@Service
public class LanuchServiceImpl implements DinnerService{
public void hava(){
System.out.println("吃饭罗");
}
public void noHave(){
System.out.println("不吃饭");
}
}
//@Aspect 定义为这是一个切面
@Aspect
@Component
public class MyAspect{
//切点---关联正则式:这里只关联hava()方法,而没有关联noHave(),因此noHave()方法不实现AOP
//注意:这里* 跟路径直接要有个空格,不然会报错
@Pointcut("execution(* com.spring.demo.service.impl.*.hava(..)"))
public void pointcut(){}
@before("Pointcut")
public void before(){System.out.println("洗手")};
@after("Pointcut")
public void after(){System.out.println("清洗餐具")};
@afterReturning("Pointcut")
public void afterReturning(){System.out.println("收拾剩饭")};
@afterThrowing("Pointcut")
public void afterThrowing(){System.out.println("处理急事去了")};
}
@Configration
@ComponentScan("com.spring.demo")
//驱动Spring AOP的注解,可以通过IOC来给管理AOP的Bean
@EnableAspectJAutoProxy
public class AppConfig{
}
public class AopMain{
public void static main(String[] args){
/*
//目标对象
DinnerService target = new LanuchServiceImpl();
//拦截器
DinnerInterceptorImpl interceptoy = new DinnerInterceptorImpl ();
//这个是获取到代理对象和目标对象的关联关系,关联起来后,代理对象就可以操作目标对象的方法了。有拦截器就追加拦截器,增强对目标对象的控制,没有也是可以的。
DinnerService proxy = (DinnerService)DinnerProxy.bind(target,interceptoy);
proxy.hava();*/
//通过Java配置文件,扫描整个项目,让IoC管理所有的Bean,这样就不需要new 对象
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
//这里有个小坑:根据IoC生成的规则:LanuchServiceImpl lanuchServiceImpl = new LanuchServiceImpl ();所以Bean的实例化是小写。个人踩坑心得 ——_——
DinnerService service = ctx.getBean("lanuchServiceImpl",DinnerService.class) ;
service.hava();//@Pointcut(execution(*( com.spring.demo.service.impl.*.hava(..))"));由于关联切点正则式,可以实现AOP
service.noHave();//不实现AOP,因为没有正则式关联整个方法
}
}
到这里就完成了整个的综合AOP基本概念的小demo。
总结一下我们写AOP的流程:
(1)确定连接点:就是你要拦截什么样的业务方法,什么方法要实现AOP这个执行过程
(2)定义好切面:切面的逻辑,定义执行过程的所有通知
(3)织入:把连接点和前面关联起来;例如切面就相当于一张没有中心点的蜘蛛网,然后你把连接点放进这张蜘蛛网,那整张蜘蛛网就连接起来了,走得通了。
(4)切点:我们需要写关联方法的正则式,意思就是哪些方法需要实现AOP的,你就需要匹配这个方法。
AOP实现简化编程的例子(数据库事务)
上图就是一个简单的数据库事务。我们只需要一个注解 @Transactional
@Transactional:开启数据库事务
这个注解的意思就是开启数据库事务,把这个方法织入到Spring AOP的整个自己实现的流程中去,达到控制程序执行流程和执行结果的目的。
AOP的优点:
1、降低模块之间的耦合度
2、使系统容易扩展
3、更好的代码复用。
AOP的缺点:
1、性能略低
2、仅适用于方法调用
3、依赖于在Spring容器