一:AOP介绍
1、什么是AOP?
l AOP为AspectOriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。 l AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码 l 经典应用:事务管理、性能监视、安全检查、缓存 、日志等 l Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码 l AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入。 |
2、AOP的实现原理
l AOP底层将采用代理机制进行实现。 l 接口 + 实现类:spring采用 jdk 的动态代理Proxy。 l 实现类:spring 采用 cglib字节码增强。 |
3、AOP的术语
1.target:目标类,需要被代理的类。例如:UserService 2.Joinpoint(连接点):所谓连接点是指那些可能被拦截到的方法。例如:所有的方法 3.PointCut 切入点:已经被增强的连接点。例如:addUser() 4.advice 通知/增强,增强代码。例如:after、before 5. Weaving(织入):是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程. 6.proxy 代理类 7. Aspect(切面): 是切入点pointcut和通知advice的结合 一个线是一个特殊的面。 一个切入点和一个通知,组成成一个特殊的面。 |
public interface UserService {
public void addUser();
public void updataUser();
public void deleUser();
}
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("add");
}
@Override
public void updataUser() {
System.out.println("up");
}
@Override
public void deleUser() {
System.out.println("dele");
}
}
public class MyAspect implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
System.out.println("前置");
// 手动执行目标方法
mi.proceed();
System.out.println("后置");
return null;
}
}
通知
public class MyAspect implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
System.out.println("前置");
// 手动执行目标方法
mi.proceed();
System.out.println("后置");
return null;
}
}
要导入的xml
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 1 创建目标类 -->
<bean id="userServiceId" class="com.itheima.c_spring_aop.UserServiceImpl"></bean>
<!-- 2 创建切面类(通知) -->
<bean id="myAspectId" class="com.itheima.c_spring_aop.MyAspect"></bean>
<!-- 3 aop编程
3.1 导入命名空间
3.2 使用 <aop:config>进行配置
proxy-target-class="true" 声明时使用cglib代理
<aop:pointcut> 切入点 ,从目标对象获得具体方法
<aop:advisor> 特殊的切面,只有一个通知 和 一个切入点
advice-ref 通知引用
pointcut-ref 切入点引用
3.3 切入点表达式
execution(* com.itheima.c_spring_aop.*.*(..))
选择方法 返回值任意 包 类名任意 方法名任意 参数任意
-->
<aop:config proxy-target-class="true">
<aop:pointcut expression="execution(* com.itheima.c_spring_aop.*.*(..))" id="myPointCut"/>
<aop:advisor advice-ref="myAspectId" pointcut-ref="myPointCut"/>
</aop:config>
</beans>
Test
public class Test1 {
@Test
public void Demo1()
{
String Xml="com/hao/d_spring_aop/bean.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(Xml);
UserService userService = (UserService) applicationContext.getBean("userServiceId");
userService.addUser();
userService.updataUser();
userService.deleUser();
}
}
5、AspectJ
5.1 AspectJ简介
l AspectJ是一个基于Java语言的AOP框架 l Spring2.0以后新增了对AspectJ切点表达式支持 l @AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面 新版本Spring框架,建议使用AspectJ方式来开发AOP l 主要用途:自定义开发. |
5.2切入点表达式
execution() 用于描述方法【掌握】 语法:execution(修饰符 返回值 包.类.方法名(参数) throws异常) 修饰符,一般省略 public 公共方法 * 任意 返回值,不能省略 void 返回没有值 String 返回值字符串 * 任意 包,[省略] com.itheima.crm 固定包 com.itheima.crm.*.service crm包下面子包任意(例如:com.itheima.crm.staff.service) com.itheima.crm.. crm包下面的所有子包(含自己) com.itheima.crm.*.service.. crm包下面任意子包,固定目录service,service目录任意包 类,[省略] UserServiceImpl 指定类 *Impl 以Impl结尾 User* 以User开头 * 任意 方法名,不能省略 addUser 固定方法 add* 以add开头 *Do 以Do结尾 * 任意 (参数) () 无参 (int) 一个整型 (int,int) 两个 (..) 参数任意 throws,可省略,一般不写。
综合1 execution(* com.hao.crm.*.service..*.*(..)) 综合2 <aop:pointcutexpression="execution(* com.hao.*WithCommit.*(..)) || execution(* com.itheima.*Service.*(..))"id="myPointCut"/> |
5.3通知类型(其一)
around:环绕通知(应用:十分强大,可以做任何事情) 方法执行前后分别执行,可以阻止方法的执行 必须手动执行目标方法 |
5.4AspectJ基于注解简单实现
1.导入Jar包
之前的4+1 l 4个: aop联盟规范 aoplliance springaop 实现 aop aspect规范 aspectj.weaver springaspect 实现 aspects |
//接口
public interface UserService {
public void addUser();
public void updataUser();
public void deleUser();
}
// 实现类
@Service("userServiceId") // 替换<bean id="userServiceId" class="com.hao.e_spring_xml.UserServiceImpl">
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("add XML");
}
@Override
public void updataUser() {
System.out.println("up XML");
}
@Override
public void deleUser() {
System.out.println("dele XML");
}
}
// 切面类
@Component // 组件
@Aspect // 替换<aop:aspect ref="myAspectId">
public class MyAspect {
@Before("exepression(* com.hao.f_spring_anno.UserServiceImpl.*(..))")
public void myBefore(JoinPoint joinPoint)
{
System.out.println("前置"+joinPoint.getSignature().getName());
}
public void myAfterreturnning(JoinPoint joinPoint,Object obj)
{
System.out.println("后置"+joinPoint.getSignature().getName());
}
//环绕
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable
{
System.out.println("前");
// 手动执行目标方法
Object proceed = joinPoint.proceed();
System.out.println("后");
return proceed;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 扫描所有注解 -->
<context:component-scan base-package="com.hao.f_spring_anno"></context:component-scan>
<!-- 2 确定aop注解生效 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!-- 创建目标类 -->
<!-- 创建切面类 -->
<!-- aop 编程
<aop:aspect> : 将切面类声明为 切面 从而使用里面的方法。ref引用切面类的ID
<aop:pointcut> : 声明一个切入点 所有的通知都可以使用。expression:切入点表达式 id 引用的名称
<aop:pointcut expression="exepression(* com.hao.e_spring_xml.UserServiceImpl.*(..))" id="myPointCut"/>
method: 切面类的方法
pointcut-ref: 共享式的引用
<aop:before method="myBefore" pointcut-ref="myPointCut"/>
-->
<!-- 环绕
<aop:around method="myAround" pointcut-ref="myPointCut"/>
-->
</beans>
//test
public class Test1 {
@Test
public void Demo1()
{
String Xml="com/hao/f_spring_anno/bean.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(Xml);
UserService userService = (UserService) applicationContext.getBean("userServiceId");
userService.addUser();
userService.updataUser();
userService.deleUser();
}
}