您的位置:首页 > 编程语言 > Java开发

Spring容器切面编程 aop注解开发 五中通知类型

2017-08-28 19:43 786 查看

AOP 编程 (aspect oriented programing )

作用

例如 权限校验 性能检测 日志记录 事物管理等操作 最重要的也是在不修改目标类的情况下对于目标类进行增强,可以跟装饰者模式对比一下

JDK CGLIB 动态代理底层原理两种

第一种 Cglib 原理

对于没有接口的类进行增强

第二种 JDK动态代理

对于有接口的类进行增强

AOP 基于XML实现

实现步骤

1. 导入需要的4个jar包 (需要了解jar包内容具体是做什么的?)

2. 申明接口 还有目标类

3. 在Spring容器中添加约束

4. 在Spring容器中申明 切面 目标类

5. 在Spring容器中配置我们切入点(目标类中方法), 代理对象中方法

<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>


目标类

public class UserServiceImp implements UserService{

@Override
public void add() {

System.out.println("刘广睿 添加了一个用户");

}


切面类

package com.ruirui.aop;

public class UserAOP {

public void AOPAdd() {

System.out.println("AOPAdd    "+ "添加成功");
}
}


spring配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

<!-- 目标类 -->
<bean id="userserviceimp" class="com.ruirui.service.imp.UserServiceImp"></bean>

<!-- 切入类 -->
<bean id="useraop" class="com.ruirui.aop.UserAOP"></bean>

<!-- 配置切入点 切入面 -->
<aop:config >
<!-- 切入点  -->
<aop:pointcut expression="execution(* com.ruirui.service.imp.UserServiceImp.add*(..))" id="pointuser1"/>

<!-- 切入面 -->
<aop:aspect ref="useraop" >

<aop:before method="AOPAdd"  pointcut-ref="pointuser1"/>

</aop:aspect>

</aop:config>

</beans>


测试

//  注意 AOP编程是属于面向接口去编程,由于userserviceimp有接口 所有需要面向父类接口去编程隐藏必须要去强转
@Test
public void method_add() {

ApplicationContext  applicationContext = new ClassPathXmlApplicationContext("beans.xml");

// 为什么向下转型 就会报出 类型转换异常
UserService userService = (UserService) applicationContext.getBean("userserviceimp");

userService.add();
}


AOP表达式

<aop:pointcut expression="execution(* com.ruirui.service.imp.UserServiceImp.add*(..))" id="pointuser1"/>

1.execution()  用于描述方法 【掌握】
语法:execution(修饰符  返回值  包.类.方法名(参数) throws异常)
修饰符,一般省略
public      公共方法
*           任意
返回值,不能省略
void            返回没有值
String      返回值字符串
*           任意
包,[省略]
com.ruirui.crm          固定包
com.ruirui.crm.*.service    crm包下面子包任意 (例如:com.ruirui.crm.staff.service)
com.ruirui.crm..            crm包下面的所有子包(含自己)
com.ruirui.crm.*.service..  crm包下面任意子包,固定目录service,service目录任意包
类,[省略]
UserServiceImpl         指定类
*Impl                   以Impl结尾
User*                   以User开头
*                       任意
方法名,不能省略
addUser                 固定方法
add*                        以add开头
*Do                     以Do结尾
*                       任意
(参数)
()                      无参
(int)                       一个整型
(int ,int)                  两个
(..)                        参数任意
throws ,可省略,一般不写。

综合1
execution(* com.ruirui.crm.*.service..*.*(..))
综合2
<aop:pointcut expression="execution(* com.ruirui.*WithCommit.*(..)) ||
execution(* com.itheima.*Service.*(..))" id="myPointCut"/>
2.within:匹配包或子包中的方法(了解)
within(com.ruirui.aop..*)
3.this:匹配实现接口的代理对象中的方法(了解)
this(com.ruirui.aop.user.UserDAO)
4.target:匹配实现接口的目标对象中的方法(了解)
target(com.ruirui.aop.user.UserDAO)
5.args:匹配参数格式符合标准的方法(了解)
args(int,int)
6.bean(id)  对指定的bean所有的方法(了解)
bean('userServiceId')


Spring 容器中的通知类型

在Spring 中通知的意义是什么? 应用场景?

前置通知

在目标方法之前执行

<!-- 切入面 -->
<aop:aspect ref="useraop" >

<aop:before method="AOPAdd"  pointcut-ref="pointuser1"/>

</aop:aspect>


后置通知

在目标方法执行之后去执行,而且有返回值,返回值是目标方法执行以后的返回值

<!-- 切入面 -->
<aop:aspect ref="useraop">

<aop:after-returning method="AOPdetle" pointcut-ref="pointuser1" returning="pp"/>

</aop:aspect>


图片插入 :



异常通知

程序出现异常时候会去执行

<!-- 切入面 -->
<aop:aspect ref="useraop">

<aop:after-throwing method="throwth"  id="pointuser1"/>
</aop:aspect>


环绕通知

可以在目标执行前后去执行其他方法

<!-- 切入面 -->
<aop:aspect ref="useraop">

<aop:around method="around" pointcut-ref="pointuser1"/>

</aop:aspect>

//环绕通知
public void around(ProceedingJoinPoint joinPoint) throws Throwable {

System.out.println("执子之手");

Object proceed = joinPoint.proceed();  //执行目标类中的插入点

System.out.println("与子偕老");

}


最终通知

就是代表无论是否会有异常 一定会执行的方法

<!-- 切入面 -->
<aop:aspect ref="useraop">

<aop:after method="finallytest" pointcut-ref="pointuser1"/>
</aop:aspect>


AOP 基于注解实现

问题 :

在使用注解的时候,如果某个方法的上面的注解出现问题,那么当前对象将无法创建实例,代表说其余的注解也会失效,简单理解就是 当前对象实例初始化失败 对应的方法也都完蛋

如果出现的问题话 一定要看看通知类型 对应的参数信息 ,还有参数的阔内部点,单词是否写错

@Component
@Aspect   //代表当前类为切面类
public class OrderAop {

@Before(value="execution(* com.ruirui.service.imp.OrderServiceImp.add(..) )")
public void beforeInform(JoinPoint joinPoint) {

System.out.println("执行之前的扫描");

System.out.println(joinPoint.getSignature().getName());
System.out.println(joinPoint.getSourceLocation().toString());
}
//返回通知
@AfterReturning(value="execution(String com.ruirui.service.imp.OrderServiceImp.delete(..))",returning="afterreturn")
public  void afterReturenInform(JoinPoint joinPoint, String afterreturn ) {

System.out.println("执行之后的扫描");

System.out.println(afterreturn);
}

@AfterThrowing(value="execution(* com.ruirui.service.imp.OrderServiceImp.find(..))",throwing="pp")
public void exceptionInform(Throwable pp) {

System.out.println("执行异常的扫描");
System.out.println(pp.toString());
}
// 环绕通知  注意参数
@Around(value="execution(* com.ruirui.service.imp.OrderServiceImp.update(..))")
public void aroundInform(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("执行环绕的扫描");

System.out.println("执子之手");

Object proceed = joinPoint.proceed();  //执行目标类中的插入点

System.out.println("与子偕老");
}
//一定执行的通知
@After(value="execution(* com.ruirui.service.imp.OrderServiceImp.finaltst(..) )")
public void finalInform() {
System.out.println("执行最终通知的扫描");

}


容器需要扫描的包

`
<!-- 开启AOP注解模式 -->

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

<!-- 扫描包 -->

<context:component-scan base-package="com.ruirui.service.imp"></context:component-scan>
<context:component-scan base-package="com.ruirui.aop"></context:component-scan>
<context:component-scan base-package="com.ruirui.service"></context:component-scan>`
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息