JDK动态代理
- 创建接口和实现类
- 创建代理类实现InvocationHandler这个接口,使用构造器传入被代理类对象,并且实现invoke方法,该方法第一个参数卵用没有,第二个参数是方法,第三个参数是方法的传参
- 要想使用方法增强就先得调用原来的方法们,可以利用反射来解决,于是利用第二个参数Method.invoke方法传入对象和参数,前后再添加增强的逻辑
- 在使用代理类的时候使用Proxy.newInstance()方法返回接口引用,第一个参数是类加载器,第二个参数需要放入接口的数组,第三个参数填入代理类对象
public class PeopleDaoImpl implements PeopleDao {
@Override
public int add(int a, int b) {
return a+b;
}
@Override
public String update(String id) {
return id;
}
}
代理类:
public class JDKProxy {
public static void main(String[] args) {
//接口的数组
Class[] interfaces = {PeopleDao.class};
PeopleDaoImpl peopleDao=new PeopleDaoImpl();
//该方法返回指定接口的代理类实例(类加载器,增强方法使用的类的接口,代理类)
PeopleDao dao = (PeopleDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new PeopleDaoProxy(peopleDao));
int add=dao.add(1,2);
System.out.println(add);
}
}
//创建代理对象代码
class PeopleDaoProxy implements InvocationHandler {
Object obj;
//有参构造传递
public PeopleDaoProxy(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;
}
}
结果
方法执行之前add传递的参数[1, 2] 方法执行之后day506AOP.PeopleDaoImpl@5197848c 3
AOP
AOP面向方面/切面编程:在不通过修改源代码的方式添加新的功能
AOP底层原理:动态代理
两种代理情况
第一种有接口:使用jdk动态代理----proxy类有newProxyInstance方法参数(类加载器,增强方法所在的类,实现接口invocationHandler,创建代理对象,写增强的方法) * 创建接口实现类的代理对象
无接口:使用CGLIB动态代理
创建当前类子类的代理对象
AOP术语:
连接点:所有可以被增强的方法
切入点:实际中被增强的方法
通知(增强):实际增强的逻辑部分,通知有多种类型:
前置:连接点之前执行 后置:之后 环绕:之前之后 异常:异常的时候执行最终 finally不管有没有都执行
切面:把通知应用到切入点的过程就叫做切面(是一个动作)
AOP操作:
AspectJ实现AOP:
注解实现:切入点表达式:知道对哪个类里面的哪个方法进行增强 * 语法结构:execution([权限修饰符][返回类型][类全路径][方法名称]([参数列表]))
举例一:对com.atguigu.dao.BookDao类里的add进行增强
*表示任意修饰符 返回类型可以省略
* execution(* com.atguigu.dao.BookDao.add(..))
参数列表用..来表示对包里所有的方法进行增强
execution(* com.atguigu.dao.BookDao.*(..))
对包里所有类所有方法进行增强 execution(* com.atguigu.dao.*.*(..))
使用aop需要在spring的依赖上添加一个依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
需要被增强的方法
public interface UserService {
void add();
}
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("方法执行");
}
}
自定义切面类
@Aspect//标注他为一个切面
public class DiyAopLog {
@Before("execution(* wym.testaop.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("执行前");
}
@After("execution(* wym.testaop.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("执行后");
}
//环绕增强中,可以给定一个参数,代表要获取处理切入的点
@Around("execution(* wym.testaop.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前");
//执行方法
Object pro=joinPoint.proceed();
System.out.println("环绕后");
}
}
xml文件
<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:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userServiceImpl" class="wym.testaop.service.UserServiceImpl"/>
<bean id="diy" class="wym.testaop.DiyAopLog"/>
<!--开启注解支持-->
<aop:aspectj-autoproxy/>
<context:annotation-config/>
</beans>
测试代码
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//使用的必须是接口而不是实现类
UserService userService = context.getBean("userServiceImpl", UserService.class);
userService.add();
}
环绕前
执行前
方法执行
执行后
环绕后
Aop执行顺序
Spring4:
正常情况: @Around前环绕通知–>@Before–>@Around后环绕通知–>@After–>@AfterReturning
异常情况:@Around前环绕通知–>@Before–>@After–>@AfterThrowing
Spring5:
正常情况:@Around前环绕通知–>@Before–>@AfterReturning–>@After–>@Around后环绕通知
异常情况:@Around前环绕通知–>@Before–>@AfterThrowing–>@After