AOP面向切面编程
1,AOP介绍
什么是AOP?
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期"动态代理"实现程序功能的统一维护的一种技术。AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。面向横向机制,取代了传统的纵向继承体系重复性代码
经典应用:性能监听,事务管理,安全检查,缓存,日志等。
springAOP在运行期间通过代理方式向目标类植入增强代码
AOP实现原理:
AOP底层将采用代理机制进行实现
常见组合,'①接口+实现类:spring采用jdk的动态代理Proxy;②spring采用cglib字节码增强
2,代理
①手动代理
JDK动态代理—手动代理,对“装饰者”设计模式简化。使用前提,必须有接口。
目标类(接口+实现类)–>切面类(A:myAspect)–>工厂类,生成代理类(Proxy)–>测试(如下)
cglib字节码增强—手动代理
没有接口,只有实现类,采用字节码增强框架cglib,在运行时,创建目标类的子类,从而对目标类进行增强;
必须导入jar包:spring-core已经整合了核心(cglib)+依赖(asm),下面由spring-core-3.2.0.RELEASE.jar解压得到哦(这里说一点,jar包其实就相当于一个压缩包),因此我们只需要导入一一个spring-core核心包即可
实例:第一,和上面相差一个接口。第二,第四个参数,就相当于执行了第二遍
这里介绍前提知识
AOP联盟为通知Advice定义了org.aopalliance.aop.Advice
Spring按照通知Advice在目标类方法的连接点位置,可以分为5类
前置通知 org.springframework.aop.MethodBeforeAdvice
在目标方法执行前实施增强
后置通知 org.springframework.aop.AfterReturningAdvice
在目标方法执行后实施增强
环绕通知 org.aopalliance.intercept.MethodInterceptor
在目标方法执行前后实施增强
异常抛出通知 org.springframework.aop.ThrowsAdvice
在方法抛出异常后实施增强
引介通知 org.springframework.aop.IntroductionInterceptor
举例:
//环绕通知,必须手动执行目标方法
try{
//前置通知
//执行目标方法
//后置通知
} catch(){
//抛出异常通知
}
②spring工厂bean代理(半自动)
让spring创建代理对象,从spring容器中手动的获取代理对象。
导入jar包:核心:4+1,依赖包:AOP:AOP联盟(规范),spring-aop.jar(spring aop实现)和com.springsource.org.aopalliance-1.0.0.jar(AOP联盟)。
实例:
③spring AOP编程(全自动)-----------这是才是核心掌握
从spring容器中获得目标类如果配置了AOP,spring将自动的生成代理。要确定目标类,aspectj切入点表达式。
导包:com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar和spring-aspects-3.2.0.RELEASE.jar
3,aspectJ
3.1 aspectJ的介绍
AspectJ是基于Java语言的AOP框架,spring2.0以后新增了AspectJ切点表达式支持。@AspectJ是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在bean类中定义切面。
主要用途:自定义开发
3.2 aspectJ的切入点表达式—必须掌握,很重要
1,execution():用于描述表达式。
语法:execution(修饰符 返回值 包.类.方法名(参数) throws 异常);
修饰符,一般省略。常用①public 公共方法;②点“.” 任意
返回值,(不能省略),void 没有返回值,String 返回字符串,点“.” 任意
包,(可省略 )
举例(两个):com.springAOP.studyProxyAuto 固定包
com.springAOP.* —springAOP包下的任意子包
类,(可省略,同包) UserServiceImpl --固定类, Impl 以Impl结尾的固定类
方法名,(不能省略)
(参数),()无参数,(int)一个整型,(int,int)两个,(…)任意
综合例子:①execution( com.springAOP.studyProxyAuto..(…))
②
2,within:匹配包或子包中的方法。
3,this:匹配实现接口的代理对象中的方法。
4,target:匹配实现接口的目标对象中的方法。
5,args匹配参数格式的符合标准的方法。
6,bean:对指定的bean
aspectJ的通知类型
AOP联盟定义的通知类型,具有特性的接口,必须实现,从而确定方法名称。
aspectJ通知类型,只定义类型名称。已有方法格式。
6种:
before:前置通知(应用:各种校验),在方法执行前执行,如果通知抛出异常,阻止方法运行。
afterReturning:后置通知(应用:常规数据处理),方法正常返回后执行,如果方法中抛出异常,通知无法执行。必须在方法执行后,所以可以获得方法的返回值。
around:环绕通知(必须掌握)(应用:十分强大,可以做任何事情),方法执行前后分别执行,可以阻止方法的执行。必须手动执行目标方法。
afterThrowing:抛出异常通知(‘应用:包装异常信息),方法抛出异常后执行,如果方法没有抛出异常,无法执行。
after:最终通知(应用:清理现场),方法执行完毕后执行,无论方法中是否出现异常。
举例:
try{
//前置:before
//手动执行目标方法
//后置:afterReturning
}catch(){
//抛出异常 afterThrowing
}finally{
//最终 after
}
jar包导入:AOP联盟规范;spring aop实现;aspect 规范;spring aspect 实现
这里可以查看到对应的通知类型
可以进去看到方法
3.3AspectJ基于xml实现
1,目标类:接口+实现;2,切面类:编写多个通知,采用AspectJ通知名称任意(方法名任意)。
3,AOP编程,将通知应用到目标类;4 测试
xml配置时,也可以看到对应的通知
实例(各大通知关于XML配置):
3.4AspectJ基于注解实现------这非常关键(必须掌握)
(和基于xml比)第一步,bean替换
并配上(作用是确定AOP注解生效)
第二步,替换AOP
替换切面类
AOP注解总结
@Aspect,声明切面,修饰切面类,从而获得通知
通知:@Before 前置;@AfterReturning 后置;@Around 环绕;@AfterThrowing 抛出异常;@After 最终;
声明切入点
@Pointcut ,修饰方法private void xxx() 之后通过”xxx()“获得切点引用
4,jdbcTemplate
jdbcTemplate模板,与数据库相关联的,与很多比如mybatis,ibatis,hibernate等
spring所提供的,用于操作JDBC工具类,类似:DBUtils
依赖:链接池DataSource
导包:spring-tx:事务;spring-jdbc:spring-jdbc开发;postgresql:加载驱动;c3p0:连接池的;dbcp:连接池核心;pool:连接池依赖
使用API(了解)
具体例子说明:
package com.springAOP.studyJDBCAPITest;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.jdbc.core.JdbcTemplate;
public class APITest {
public static void main(String[] args){
//创建数据源(连接池)dbcp
BasicDataSource dataSource = new BasicDataSource();
//基本事项
//org.postgresql.Driver
//jdbc:postgresql://localhost/myDB
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUrl("jdbc:postgresql://localhost/zhouyi");
dataSource.setUsername("postgres");
dataSource.setPassword("823328");
//创建模板
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
//通过API,如果是mybatis,ibatis,hibernate,save保存下即可。而且下面的操作通常放在XML中去执行
jdbcTemplate.update("insert into t_user(id,user_name,password) values(?,?,?)","3","tom","998");
}
}
JdbcDaoSupport
通过继承JdbcDaoSupport,来实现模板注入,通过this.getJdbcTemplate()来获取
配置文件
源码分析:
结合配置文件