04-Spring框架之AOP
文章目录 2、AOP(底层原理) 2.2、AOP(JDK 动态代理) 3、AOP(术语) 4、AOP操作(准备工作) 5、AOP操作(注解) 6、AOP操作(配置文件)
1、AOP概念 1.1、什么是AOP 2、AOP(底层原理) 2.1、AOP底层使用动态代理 2.1.1、第一种 有接口情况,使用JDK动态代理 2.1.2、第二种 没有接口情况,使用CGLIB动态代理 2.2、AOP(JDK 动态代理) 2.2.1、使用JDK动态代理,使用Proxy类里面的方法创建代理对象
java.lang.reflectClass Proxy
java.lang.Objectjava.lang.reflect.Proxy
调用方法
@CallerSensitivepublic static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
方法有三个参数:
第一参数:类加载器
第二参数:增强方法所在的类,这个类实现的接口,支持多个接口
第三参数:实现这个接口,创建代理对象,写增强的部分
2.2.2、编写JDK动态代理代码 2.2.2.1、创建接口,定义方法
public interface UserDao {public int add(int a,int b);public String update(String id);
}
2.2.2.2、创建接口实现类,实现方法
public class UserDaoImpl implements UserDao{@Overridepublic int add(int a, int b) {return a+b;}@Overridepublic String update(String id) {return id;}
}
2.2.2.3、使用Proxy类创建接口代理对象
public class JDKProxy { public static void main(String[] args) { //创建接口实现类代理对象 Class[] interfaces={UserDao.class};
// Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
// @Override
// public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// return null;
// }
// }); UserDaoImpl userDao=new UserDaoImpl(); UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao)); int result =dao.add(1,2); System.out.println("result:"+result); }
} // 创建代理对象代码
class UserDaoProxy implements InvocationHandler{ //1、把创建的是谁的代理对象,把谁传递过来 //有参构造传递 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)); // 被增强的方法执行 Object res = method.invoke(obj, args); // 方法之后 System.out.println("方法之后执行..."+obj); return res; }
}
运行结果
3、AOP(术语) 3.1、连接点
类里面哪些方法可以被增强,这些方法称为连接点
3.2、切入点
实际被增强的方法,称为切入点
3.3、通知(增强) 3.4、切面
是动作,把通知应用到切入点过程
4、AOP操作(准备工作) 4.1、框架一般都是基于实现AOP操作
不是组成部分,独立于AOP框架,一般把和框架一起使用,进行AOP操作
4.2、基于实现AOP操作
1)基于xml配置文件实现
2)基于注解方式实现
4.3、在项目工程里面引入AOP相关依赖
##
4.4、切入点表达式
1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强
2)语法结构:([权限修饰符][返回类型][类全路径][方法名称] ([参数列表]))
举例1:对com.pgh.dao.类里面的add进行增强
(* com.pgh.dao..add*(…))
举例2:对com.pgh.dao.类里面的所有的方法进行增强
(* com.pgh.dao..(…))
举例3:对com.pgh.dao包里面的类,类里面所有方法进行增强
( com.pgh.dao..(…))
5、AOP操作(注解) 5.1、创建类,在类里面定义方法
public class User {public void add(){System.out.println("add......");}
}
5.2、创建增强类(编写增强逻辑)
在增强类里面,创建方法,让不同方法代表不同通知类型
// 增强的类
public class UserProxy {public void before(){// 前置通知System.out.println("before...");}
}
5.3、进行通知的配置
<?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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!--开启注解扫描--><context:component-scan base-package="pgh.aop.testAspectJ"></context:component-scan>
</beans>
<!--开启Aspect生成代理对象--><aop:aspectj-autoproxy></aop:aspectj-autoproxy>
5.4、配置不同类型的通知
在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置
@Component
@Aspect
// 增强的类
public class UserProxy {// 前置通知// @Before注解表示作为前置通知@Before(value="execution(* pgh.aop.testAspectJ.User.add(..))")public void before(){System.out.println("before......");}// 后置通知(返回通知)@AfterReturning(value = "execution(* pgh.aop.testAspectJ.User.add(..))")public void after(){System.out.println("after......");}// 异常通知@AfterThrowing(value = "execution(* pgh.aop.testAspectJ.User.add(..))")public void afterThrowing(){System.out.println("afterThrowing......");}// 环绕通知@Around(value = "execution(* pgh.aop.testAspectJ.User.add(..))")public void around(ProceedingJoinPoint processingJoinPoint) throws Throwable{System.out.println("环绕之前");// 被增强的方法执行processingJoinPoint.proceed();System.out.println("环绕之后.....");}
}
测试结果
5.5、相同的切入点抽取
//相同切入带你抽取@Pointcut(value = "execution(* pgh.aop.testAspectJ.User.add(..))")public void pointdemo(){}// 前置通知// @Before注解表示作为前置通知@Before(value="pointdemo()")public void before(){System.out.println("before......");}
5.6、有多个增强类多同一个方法进行增强,设置增强类优先级
在增强类上面添加注解@Order(数字类型值),数字类型值越小优先级越高
@Component
@Aspect
@Order(1)
// 增强的类
public class UserProxy {
5.7、完全使用注解开发
创建配置类,不需要创建xml配置文件
@Configuration
@ComponentScan(basePackages = {"pgh.aop.testAspectJ"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop {
}
6、AOP操作(配置文件) 6.1、创建两个类,增强类和被增强类,创建方法(我就用上面的) 6.2、在配置文件中创建两个类对象
<!--创建对象--><bean id="user" class="pgh.aop.testAspectJ.User"></bean><bean id="userProxy" class="pgh.aop.testAspectJ.UserProxy"></bean>
6.3、在配置文件中配置切入点
<!--配置aop增强--><aop:config><!--切入点--><aop:pointcut id="p" expression="execution(* pgh.aop.testAspectJ.User.add(..))"/><!--配置切面--><aop:aspect ref="userProxy"><!--增强作用在具体的方法上--><aop:before method="before" pointcut-ref="p"></aop:before></aop:aspect></aop:config>