day3 springAOP
AOP,面向切面开发。在不修改源代码的基础上增加新的功能。
AOP 底层原理
底层使用动态代理
-
有 接口(使用 jdk 的动态代理)
创建有接口的实现类的代理对象,使用代理对象增强功能方法 。
接口,调用
newProxyInstance
方法class Proxy{ static object newProxyInstance(ClassLoader loader,类<?>[] interfaces,InvocationHandler h) } 参数1:类加载器 参数2:增强方法所在类实现的接口,支持多个接口 参数3:需要实现的接口,创建对象,增强部分
代码
interface UserDao { public int add(int a,int b); public String update(String id); } class UserDaoImpl implements UserDao{ @Override public int add(int a, int b) { return a+b; } @Override public String update(String id) { return id; } } class UserDaoProxy implements InvocationHandler{ private Object obj; public UserDaoProxy(Object obj){ this.obj = obj; } // 增强的逻辑 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 方法之前 System.out.println("方法前执行..."+method.getName()+"; 参数:"+ Arrays.toString(args)); // 方法执行 // invoke 参数1:实现类对象, 参数2:传入参数 Object res = method.invoke(obj, args); // 方法之后执行 System.out.println("方法执行后..."); return res; } } class JDKProxy { public static void main(String[] args) { // 创建接口实现类的代理对象 Class[] interfaces = {UserDao.class}; UserDaoImpl userDao = new UserDaoImpl(); UserDao user = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao)); int res = user.add(12, 5); System.out.println(res); } }
-
没有接口(使用 cglib 的动态代理)
创建当前类的子类代理对象,增强类的方法
AOP术语
1.连接点
2.切入点
3.通知(增强)
class User{
add(){}
update(){}
}
-
连接点
类中哪些方法可以被增强,这些方法为连接点
-
切入点
实际被增强的方法,称为切入点
-
通知(增强)
(1) 实际增强的逻辑部分称为通知(增强)
(2) 通知分为多种类型
- 前置通知 方法前执行
- 后置通知 方法后执行
- 环绕通知 方法前后都执行
- 异常通知 方法出现异常执行
- 最终通知 最终执行,finally
- 前置通知 方法前执行
-
切面
动作,指把通知应用到切入点的过程
AOP 操作
-
Spring 框架一般都是基于 AspectJ 实现 AOP 操作
AspectJ 是一个独立的 aop 框架,一般把 AspectJ 和 spring 框架一起使用,进行 AOP 操作
-
基于 AspectJ 实现 aop
- 基于 xml 配置文件实现
- 基于注解的方式实现
-
在项目工程中引入相关依赖 jar
-
切入点表达式
-
作用:知道对哪个类里的哪个方法进行增强
-
语法结构
execution( [权限修饰符] [返回类型] [类的全路径] [方法名] [参数列表])
例子
execution( * com.edu.test.add(..))
-
基于 AspectJ 注解,实现AOP操作
-
创建类,在类中定义方法
@Component // 生成对象 public class User { public void add(){ System.out.println("方法执行"); } }
-
创建增强类,编写增强逻辑
在增强类里,创建方法,让不同方法代表不同通知类型
@Component // 生成对象 @Aspect // 设置增强类 public class UserProxy { public void before(){ System.out.println("before..."); } }
-
进行通知的配置
(1) 在 spring 配置文件中,开启注解扫描
(2) 使用注解创建 User 和 UserProxy 对象
(3) 在增强类上添加注解 @Aspect
(4) 在 spring 配置文件中开启生成代理对象的配置
spring 配置文件 添加命名空间 context、aop <!-- 开启注解扫描 --> <context:component-scan base-package="com.edu"></context:component-scan> <!-- 开启 Aspect 生成代理对象 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <!-- 找到声明 Aspect 的类声明为注解对象 -->
-
配置不同类型的通知
在增强类的里边,在作为通知的方法上边,添加通知类型的注解,并使用切入点表达式来配置内容。
@Before( value=" execution( * com.edu.user.add(…)) " )
-
测试
@Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); User user = context.getBean("user",User.class); user.add(); }
其他注解
- @After(value="") 结束后执行,最终通知,即使有报错也会通知
- @AfterReturning(value="") 结束并返回后执行
- @AfterThrowing(value="") 异常通知
- @Around(value="") 环绕通知
顺序
环绕之前
before
方法
环绕之后
after
afterReturning
- 关于 相同的切入点抽取
@Pointcut(value="execution( * com.edu.user.add(...))")
public void pointDemo(){
}
@Before(value="pointDemo()")
public void before(){
}
@After(value="pointDemo()")
public void after(){
}
-
有多个增强类对同一个方法进行增强,设置增强类优先级
在增强类上添加一个注解 @Order(value) ,value值越小,优先级越高
@Component @Aspect @Order(1) public class UserProxy{}
基于 AspectJ 配置文件,实现AOP操作
1. 创建两个类,增强类和被增强类,创建方法
2. 在 spring 配置文件中创建两个类对象
3. 在 spring 配置文件中配置切入点
完全注解开发
使用注解,完全替代xml配置
@Configuration
@ComponentScan(basePackages = {"com.edu"}) //扫描
@EnableAspectJAutoProxy(proxyTargetClass = true) //开启AspectJ生成代理对象
public class ConfigAop{
}