SpringAOP

------------恢复内容开始------------

Spring AOP

面向切面编程,举个例子,在一个项目中在不改变原有的代码情况下添加一个权限管理,去掉权限管理模块也不回对原有的代码有任何影响。也就是说在不改变原来的代码条件,增强原有的方法,这就是面向切边编程。

AOP动态代理

AOP动态代理有两种情况:

 

SpringAOP

2、没有接口的情况,使用Cglib动态代理, Spring AOP 会使用 Cglib 生成一个被代理对象的子类来作为代理,增强类的方法

SpringAOP

JDK动态代理

1、使用JDK动态代理,使用Proxy类里面的方法创建代理对象:

  调用newProxyInstance方法,方法有三个参数:

    第一个参数:类加载器;

    第二个参数:增强方法所在的类,这个类实现的接口,支持多个接口,这个参数是个数组;

    第三个参数:实现这个接口InvocationHandler,创建代理对象,写增强的方法。

SpringAOP

 

模拟JDK动态代理

模拟底层的动态代理实现原理

  1)创建接口

1 public interface UserDao {
2     public int add(int a,int b);
3 
4     public String update(String id);
5 }

  2)实现接口

 1 import com.riven.dao.UserDao;
 2 
 3 public class UserDaoImpl implements UserDao {
 4     @Override
 5     public int add(int a, int b) {
 6         System.out.println("add方法执行了");
 7         return a+b;
 8     }
 9 
10     @Override
11     public String update(String id) {
12         return id;
13     }
14 }

  3)编写代理代码

 1 package com.riven.test;
 2 
 3 import com.riven.dao.UserDao;
 4 import com.riven.impl.UserDaoImpl;
 5 
 6 import java.lang.reflect.InvocationHandler;
 7 import java.lang.reflect.Method;
 8 import java.lang.reflect.Proxy;
 9 import java.util.Arrays;
10 
11 public class JDKProxy {
12     public static void main(String[] args) {
13         //创建接口实现类代理对象
14         Class[] interfaces = {UserDao.class};
15         /*方式一:第三个参数使用匿名内部类方式创建代理对象,编写增强类代码
16         Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
17             @Override
18             public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
19                 return null;
20             }
21         });
22         */
23 //        方式二:
24         //要被代理的对象
25         UserDaoImpl userDao = new UserDaoImpl();
26         //返回代理对象
27         UserDao dao =(UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),interfaces,new UserDaoProxy(userDao));
28         int result = dao.add(1,2);
29         System.out.println("result = " + result);
30     }
31 }
32 //方式二
33 //创建代理对象代码
34 class UserDaoProxy implements InvocationHandler{
35     private Object obj;
36     //1、创建的是谁的代理对象,把谁传递进来
37     //有参构造传递
38     public UserDaoProxy(Object obj){
39         this.obj = obj;
40     }
41     //增强的逻辑
42     @Override
43     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
44         /**
45          * proxy: 代理对象
46          * method:当前的方法
47          * args:存放传递的参数
48          */
49 
50         //方法之前
51         System.out.println("方法之前执行..." + method.getName() + ":传递的参数..."+ Arrays.toString(args));
52         //被增强的方法执行
53         //传入被代理的对象、调用该方法的参数
54         Object res = method.invoke(obj,args);
55         //方法之后
56         System.out.println("方法执行之后..." + obj);
57         return res;
58     }
59 }

Spring对动态代理做了封装,我们可以通过配置,然后调用Spring内的动态代理。

AOP术语

  1)连接点

    类里面哪些方法可以被增强,这些方法称为连接点。

  2)切入点

    实际被增强了的方法,称为切入点。

  3)通知(增强)

    (1)实际增强的逻辑部分称为通知(增强)

    (2)通知有多种类型

      1、前置通知:增强方法之前,前置通知会执行;

      2、后置通知:增强方法之后,后置通知会执行;

      3、环绕通知:增强方法之前之后,环绕通知都会执行;

      4、异常通知:增强的方法出现异常,异常通知会执行;

      5、最终通知:最终通知类似finally,无论会不会出现异常都会执行。

 

  4)切面

     是一个动作,把通知应用到切入点的过程。例如,为登录方法添加权限管理功能的过程。

AOP操作准备

1、Spring框架一般都是基于AspectJ实现AOP操作

  1)什么是AspectJ

    AspectJ不是Spring组成部分,它是独立AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作

2、基于AspectJ实现AOP操作

  1)基于xml配置文件实现

  2)基于注解方式实现(推荐)

3、引入AOP依赖

4、切入点表达式

  1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强

  2)语法结构

    execution([权限修饰符] [返回类型] [类全路径] [方法名称]([参数列表]))

    举例1:对com.springaop.UserDao类里面的add进行增强

      execution(* com.springaop.UserDao.add(..)):

        * com.springaop.UserDao.add(..):*:表示任意权限修饰符,返回类型可以不写(这里没写)类全路径点方法名,".." 表示所有参数。

    举例3:对com.springaop.UserDao类里面的所有方法进行增强

      execution(* com.springaop.UserDao.*(..)):

 

AOP示例演示

1、创建类,在类里面定义方法

1 //被增强的类
2 public class User {
3     public void add(){
4         System.out.println("add...");
5     }
6 }

2、创建增强类(编写增强逻辑)

1 //增强的类
2 public class UserProxy {
3     //前置通知
4     public void before(){
5         System.out.println("before....");
6     }
7 }

3、进行通知的配置

  1)在 spring 配置文件中,开启注解扫描

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xmlns:context="http://www.springframework.org/schema/context"
 5        xmlns:aop="http://www.springframework.org/schema/aop"
 6        xmlns:p="http://www.springframework.org/schema/p"
 7        xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
 8        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
 9   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
10 ">
11 
12     <!-- 自动扫描
13     base-package值为扫描该包下(包括子包)的所有类
14     -->
15     <context:component-scan base-package="com.riven.aopanno"></context:component-scan>
16 
17     <!-- 是Aspect注解生效,为目标类自动生成代理对象 -->
18     <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
19 
20 </beans>

  

  2)使用注解创建 User 和 UserProxt

    在这两个类上添加 @Component 注解

 

  3)在增强类上面添加注解  @Aspect

    SpringAOP

 

  4)在 spring配置文件中开启生成代理对象

    SpringAOP

 

4、配置不同类型的通知

  1)在增强类的里面,在作为通知方法上面添加通知类行注解,使用切入点表达式配置

 1 import org.aspectj.lang.annotation.Aspect;
 2 import org.aspectj.lang.annotation.Before;
 3 import org.springframework.stereotype.Component;
 4 
 5 //增强的类
 6 @Component
 7 @Aspect //生成代理对象
 8 public class UserProxy {
 9 
10     //前置通知
11     @Before(value = "execution(* com.riven.aopanno.User.add(..))")
12     public void before(){
13         System.out.println("before....");
14     }
15 }

 

 5、相同的切入点抽取

 1 //相同切入点抽取
 2     @Pointcut(value = "execution(* com.riven.aopanno.User.add(..))")
 3     public void pointdemo(){
 4         
 5     }
 6     //前置通知
 7     @Before(value = "pointdemo()")
 8     public void before(){
 9         System.out.println("你人呢before....");
10     }

 

6、有多个增强类对同一个方法进行增强,进行设置优先级

   1)在增强类上面添加注解@Order(数字类型值),数字类型值越小优先级越高

UserProxy

 1 //被增强的类
 2 @Component
 3 @Aspect //生成代理对象
 4 @Order(2)
 5 public class UserProxy {  
6 //相同切入点抽取
7 @Pointcut(value = "execution(* com.riven.aopanno.User.add(..))")
8 public void pointdemo(){
9
10 }
11 //前置通知
12 @Before(value = "pointdemo()")
13 public void before(){
14 System.out.println("你人呢before....");

15 }
16 @AfterReturning(value = "execution(* com.riven.aopanno.User.add(..))")
17 public void afterReturning(){
18 System.out.println("你人呢afterReturning....");
19 }
20 @After(value = "execution(* com.riven.aopanno.User.add(..))")
21 public void aftere(){
22 System.out.println("你人呢after....");
23 }
24 @AfterThrowing(value = "execution(* com.riven.aopanno.User.add(..))")
25 public void afterThrowing(){
26 System.out.println("你人呢afterThrowing....");
27 }
28 //环绕通知,在方法执行之前之后都会执行
29 //方法执行之前先执行这个方法然后再执行前置通知
30 //方法执行之后先执行这个方法然后在执行后置通知
31 @Around(value = "execution(* com.riven.aopanno.User.add(..))")
32 public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
33 System.out.println("环绕之前.....");
34
35 //被增强的方法执行
36 proceedingJoinPoint.proceed();
37
38 System.out.println("环绕之后....");
39 }
40 }

新创建UserProxy2

 1 package com.riven.aopanno;
 2 
 3 import org.aspectj.lang.annotation.Aspect;
 4 import org.aspectj.lang.annotation.Before;
 5 import org.springframework.core.annotation.Order;
 6 import org.springframework.stereotype.Component;
 7 
 8 @Component
 9 @Aspect
10 @Order(1)
11 public class UserProxy2 {
12     @Before(value = "execution(* com.riven.aopanno.User.add(..))")
13     public void before(){
14         System.out.println("你人呢before2....");
15     }
16 }

创建运行类

1 public class TestAOP {
2     public static void main(String[] args) {
3         ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
4         User user = context.getBean("user", User.class);
5         user.add();
6     }
7 }

运行结果:

1、没有出现异常

先运行UserProxy2的 @Before ==> UserProxy的@Around环绕(前)代码 ==> @Before ==> 执行被增强方法内容 ==> @Around环绕(后)代码 ==> @After ==>@AfterReturning

2、出现异常

先运行UserProxy2的 @Before ==> UserProxy的@Around环绕(前)代码 ==> @Before ==> @After ==>@AfterThrowing

 

  2)使用配置文件

上一篇:Latex 双栏模式下表格太长怎么办?


下一篇:Latex【一】 表格整体居中