文章目录
AOP
- 什么是aop 面向切面编程 (面向方面编程)
- 利用aop以对业务逻辑的各个部分进行隔离 从而使得业务逻辑各个部分之间耦合度降低 提高程序的可重用性 同时提高了开发的效率
aop 想添加功能 但是不修改源代码 在主干功能里添加新功能
aop ( 底层原理 )
AOP 的底层 使用 动态代理
- 有两种情况的动态代理
- 有接口的情况 使用 JDK动态代理
- 没有接口的情况 使用CGLIB动态代理
aop jdk动态代理
-
使用jdk 动态代理,使用Proxy类中的方法 创建代理对象
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException
- 方法中含有三个参数
- 第一个 类加载器
- 第二个 增强方法所在的类 这个类实现的接口 支持多个接口
- 第三个 实现这个接口 InvocationHandler 创建代理对象
- 方法中含有三个参数
-
jdk 动态代理代码
-
创建接口 定义方法
package com.zh.demo1; public interface UserDao { public int add(int a,int b); public String update(String id); }
-
创建接口的实现类 实现方法
package com.zh.demo1; public class UserDaoImpl implements UserDao{ @Override public int add(int a, int b) { return a+b; } @Override public String update(String id) { return id; } }
-
使用Proxy类创建接口代理对象
- 创建一个类 创建main方法
- 实现Proxy中newProxyInstance 方法 方法含有三个参数 上边写了 第一个参数是类的加载器 为JDKProxy.class.getClassLoader() 第二个参数为增强方法所在的类 举例为userdao 第三个参数一个接口用来创建代理对象 两种方法 1 匿名内部类 直接new 2 创建一个新的类实现此接口 我采用的为此方法
package com.zh.demo1; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays; public class JDKProxy { private Object object; public static void main(String[] args) { //创建接口实现类的代理对象 Class[] interfaces={UserDao.class}; UserDaoImpl userDao=new UserDaoImpl(); UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao)); int add=dao.add(1,2); System.out.println(add); } } //创建代理对象代码 class UserDaoProxy implements InvocationHandler{ //1 把创建的是 谁的代理对象 把谁传递过来 //通过有参构造进行传递 private Object object; public UserDaoProxy(Object object){ this.object=object; } //增强的逻辑 @Override //第一个参数 代理对象 第二个值 表示当前的方法 第三个 表示方法的参数 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //方法之前 //method.getName()执行的方法名字 System.out.println("方法之前执行"+method.getName()+":传递的参数====="+ Arrays.toString(args)); //被增强的方法 //下面表示执行当前方法 Object a=method.invoke(object,args); //方法之后 System.out.println("方法之后执行 "+object); return a; } }
-
aop 术语
- 连接点 类里的哪些方法可以被增强 这些方法被称为连接点
- 切入点 实际被真正增强的方法 被称为切入点
- 通知(增强)
- 实际增强的逻辑的部分称为通知
- 通知有多种类型
- 前置通知 @before
- 后置通知 @afterReturning
- 环绕通知 @around
- 异常通知 @afterThrowing
- 最终通知 @after
- 切面 是动作 把通知应用到切入点的过程
aop操作 (准备)
- spring 框架一般都是基于aspectJ实现aop 操作
- 什么是AspectJ AspectJ不是spring组成部分 是独立aop框架 一般吧AspectJ和spring框架一起使用 进行aop操作
- 基于AspectJ实现aop操作
- 基于xml配置文件实现
- 基于注解方式实现
- 在项目工程中引入aop相关依赖
- 切入点表达式
- 作用: 知道对哪个类里面的方法进行增强
- 语法结构 :execution([权限修饰符] [返回类型] [方法名称] ([参数列表]))
- 举例1 execution(* con.zh.demo1.Book.add(…)) *表示所有的修饰符
- 举例2 对类里的所有方法进行增强 execution(* com.zh.demo.Book.*(…))
- 举例3 对包中的所有类 类里的所有方法进行增强execution(* com.zh.* . *(…))
aop操作(基于AspectJ注解方式)
-
创建一个类 在类中定义方法,实现对类的方法增强
-
创建一个增强类,编写增强的逻辑
- 在增强类中创建方法 让不同的方法代表不同的通知类型
-
进行通知的配置
-
在spring配置文件中 开启注释
<?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/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"> <!-- 开启注解的扫描--> <context:component-scan base-package="com.zh"></context:component-scan>
-
使用注解创建user和userproxy两个对象
//被增强的类 @Component public class User { public void add(){ System.out.println("add............."); } } //增强的类 @Component @Aspect//生成代理对象 public class UserProxy { //前置通知 public void before(){ System.out.println("before........."); } }
-
在增强的类上添加一个注解 @aspect
//增强的类 @Component @Aspect//生成代理对象 public class UserProxy { //前置通知 public void before(){ System.out.println("before........."); } }
-
在spring配置文件中 开启生成代理对象`
<!-- 开启aspectJ生成代理对象--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
-
配置不同类型的通知
-
在我们增强类的里边 在作为通知方法上面 添加通知类型注解 使用切入点表达式配置
//前置通知 //before 注解表示作为前置通知 @Before(value = "execution(* com.zh.demo2.User.add())") public void before(){ System.out.println("before........."); }
//环绕通知 在add之间 和之后都执行 @Around(value = "execution(* com.zh.demo2.User.add())") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕之前"); //执行被增强的方法 proceedingJoinPoint.proceed(); System.out.println("环绕之后"); }
before 前置通知 afterthrowing 异常通知 产生异常 才会执行after 最终通知 有异常也执行
-
-
对公共切入点抽取
//相同切入点抽取 @Pointcut(value = "execution(* com.zh.demo2.User.add())") public void pointdemo(){ } //前置通知 //before 注解表示作为前置通知 @Before(value ="pointdemo()") public void before(){ System.out.println("before........."); }
-
有多个增强类对同一个方法进行增强 设置增强类的优先级
-
在增强类上面添加一个注解 @Order(数字类型值) 数字类型值越小 优先级越高
//增强的类 @Component @Aspect//生成代理对象 @Order(3) public class UserProxy {} ======================================================== @Component @Aspect @Order(1) public class PersonProxy { @Before(value = "execution(* com.zh.demo2.User.add())") public void before(){ System.out.println("person before........."); } }
-
-
aop操作(AspectJ配置文件方式)
-
创建两个类 增强类和被增强类 创建方法
-
在spring配置文件中创建两个类对象
创建对象 <bean id="book" class="com.zh.demo3.Book"></bean> <bean id="bookProxy" class="com.zh.demo3.BookProxy"/>
-
在spring配置文件中配置切入点
<!-- 配置aop增强 --> <aop:config> <!-- 切入点--> <aop:pointcut id="zh" expression="execution(* com.zh.demo3.Book.buy())"/> <!-- 配置切面 表示把增强的方法应用到切入点的过程--> <aop:aspect ref="bookProxy"> <!-- 配置 增强作用在具体的方法上 method 增强的方法 pointcut-ref作用在哪个切入点--> <aop:before method="before" pointcut-ref="zh"/> </aop:aspect> </aop:config>
完全注解(简单了解)
创建一个配置类 不需要创建xml配置文件
package com.zh.demo3;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan(basePackages = {"com.zh.demo3"})//替代配置文件中 开启组件扫描
@EnableAspectJAutoProxy(proxyTargetClass = true)//替代配置文件中 开启aspect生成代理对象
public class ConfigAop {
}