跟随尚硅谷学习Spring5
AOP(面向切面编程)
static object nevProxyInstance(ClassLoader loader,类<?>[] interfaces,InvocationHandler h)
返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。
该方法有三个参数:
第一参数,类加载器
第二参数,增强方法所在的类,这个类实现的接口,支持多个接口
第三参数,实现这个接口 InvocationHandler,创建代理对象,写增强的部分
package com.atguigu.spring5.aop.jdk.dao;
public interface UserDao {
public int add(int a, int b);
public void sendMsg(String msg);
}
package com.atguigu.spring5.aop.jdk.dao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoImpl implements UserDao {
public int add(int a, int b) {
System.out.println("UserDaoImpl.add()方法执行了");
return a + b;
}
public void sendMsg(String msg) {
System.out.println("UserDaoImpl.sendMsg()方法执行了,内容为:" + msg);
}
}
创建接口实现类,实现方法
package com.atguigu.spring5.aop.jdk.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;
// 创建代理对象代码
class UserDaoProxy implements InvocationHandler {
// 1、创建谁的代理对象,把谁传递过来;这里为了通用一些,写成Object
private Object object;
// 有参数构造传递
public UserDaoProxy(Object object) {
this.object = object;
}
// 增强的逻辑,需要传入被代理的接口
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 方法之前
System.out.println("UserDaoProxy.invoke() - 方法之前执行了,方法名为:" + method.getName() + ":传递的参数..." + Arrays.toString(args) + "当前对象:" + object);
// 被增强的方法执行
Object res = method.invoke(object, args);
// 方法之后
System.out.println("UserDaoProxy.invoke() - 方法之后执行了,方法名为:" + method.getName() + ":传递的参数..." + Arrays.toString(args) + "当前对象:" + object);
return res;
}
}
package com.atguigu.spring5.aop.jdk.proxy;
import com.atguigu.spring5.aop.jdk.dao.UserDao;
import com.atguigu.spring5.aop.jdk.dao.UserDaoImpl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class JDKProxy {
public static void main(String[] args) {
Class[] interfaces = {UserDao.class};
UserDaoImpl userDaoImpl = new UserDaoImpl();
// 创建接口实现类的代理对象
// 写法1, InvocationHandler使用匿名内部类
/*
Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
});
*/
// 写法2:不使用InvocationHandler匿名内部类;而是使用一个实现InvocationHandler的代理类实例
// 接口 = 实现类
/**
* Proxy.newProxyInstance()方法参数说明:
* 第一个参数:当前类自身的类加载器;
* 第二个参数:需要被代理的类所实现的(一个或多个)接口
* 第三个参数:InvocationHandler接口实现类,写增强的地方,这里需要传入被代理的实现类对象"userDaoImpl"
*/
UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDaoImpl));
System.out.println("\n---------- 开始测试第一个方法:有返回值 ----------");
int result = dao.add(1, 2);
System.out.println("返回值为:" + result);
System.out.println("\n---------- 开始测试第二个方法:没有返回值 ----------");
dao.sendMsg("你好啊");
}
}
举例 1:
对 com.atguigu.dao.BookDao 类里面的 add 进行增强
execution(* com.atguigu.dao.BookDao.add(..))
举例 2:
对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强
execution(* com.atguigu.dao.BookDao.* (..))
举例 3:
对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强
execution(* com.atguigu.dao.*.* (..))
package com.atguigu.spring5.aop.annotation;
import org.springframework.stereotype.Component;
//需要被增强的类
@Component
public class User {
public void add() {
// int i = 10/0; // 这里用于测试抛出异常情况
System.out.println("User.add()...");
}
}
//增强的类
public class UserProxy {
public void before() {//前置通知
System.out.println("before.. . ...");
}
}
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 完全注解写法可以消除该配置文件,写法如下
1、创建一个配置类在类里面添加如下注解
@Configuration
@ComponentScan(basePackages = {"com.atguigu"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class SpringConfig {
}
-->
<!--开启组件扫面 - 等同于 @ComponentScan(basePackages = {"com.atguigu"})-->
<context:component-scan base-package="com.atguigu.spring5.aop.annotation"/>
</beans>
(2)使用注解创建 User 和 UserProxy 对象
@Component
public class User {
//增强的类
@Component
public class UserProxy {
(3)在增强类上面添加注解 @Aspect
//增强的类
@Component
@Aspect // 生成代理对象
public class UserProxy {
(4)在 spring 配置文件中开启生成代理对象
<!--开启Aspect生成代理对象 - 等同于 @EnableAspectJAutoProxy(proxyTargetClass = true)-->
<aop:aspectj-autoproxy/>
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
//增强的类
@Component
@Aspect // 生成代理对象
public class UserProxy {
//环绕通知 - 之前之后都执行
@Around(value = "execution(* com.atguigu.spring5.aop.annotation.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("UserProxy.around()...环绕之前");
System.out.println("UserProxy.around()...环绕之后");
}
//前置通知
@Before(value = "execution(* com.atguigu.spring5.aop.annotation.User.add(..))")
public void before() {
System.out.println("UserProxy.before()...前置通知");
}
//后置通知(最终通知)
@After(value = "execution(* com.atguigu.spring5.aop.annotation.User.add(..))")
public void after() {
System.out.println("UserProxy.after()...后置通知(最终通知)");
}
//后置返回通知(返回结果执行)
@AfterReturning(value = "execution(* com.atguigu.spring5.aop.annotation.User.add(..))")
public void afterReturning() {
System.out.println("UserProxy.afterReturning()...后置返回通知(返回结果执行)");
}
//异常通知
@AfterThrowing(value = "execution(* com.atguigu.spring5.aop.annotation.User.add(..))")
public void afterThrowing() {
System.out.println("UserProxy.afterThrowing()...异常通知");
}
}
(2)总结
@AfterReturning方法之后通知,在返回结果之后执行,有异常不执行
@AfterThrowing有异常才通知
@After方法之后通知,直接在方法后执行,有异常也执行
@Before方法之前通知
@Around方法之前和之后都通知
//增强的类
@Component
@Aspect // 生成代理对象
public class UserProxy {
@Pointcut(value = "execution(* com.atguigu.spring5.aop.annotation.User.add(..))")
public void pointcutAddMethod() {
}
//环绕通知 - 之前之后都执行
@Around(value = "pointcutAddMethod()")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("UserProxy.around()...环绕之前");
System.out.println("UserProxy.around()...环绕之后");
}
}
@Component
@Aspect // 生成代理对象
@Order(1) // 在增强类上添加注解@Order(数字类型值),数字类型值越小优先级越高
public class UserProxy {
@Component
@Aspect // 生成代理对象
@Order(2) // 在增强类上添加注解@Order(数字类型值),数字类型值越小优先级越高
public class UserProxy2 {
//增强的类
@Component
@Aspect // 生成代理对象
@Order(3) // 在增强类上添加注解@Order(数字类型值),数字类型值越小优先级越高
public class UserProxy3 {
@Configuration
@ComponentScan(basePackages = {" com. atguigu"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop {
}
以上几项操作测试:
package com.atguigu.sprint5;
import com.atguigu.spring5.aop.annotation.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAop {
@Test
public void testAopAnnotations() {
ApplicationContext context = new ClassPathXmlApplicationContext("aop.xml");
User user = context.getBean("user", User.class);
user.add();
}
}
创建两个类,增强类和被增强类,创建方法
package com.atguigu.spring5.aop.xml;
//需要被增强的类
public class User {
public void add() {
System.out.println("User.add()...");
}
}
package com.atguigu.spring5.aop.xml;
//增强的类
public class UserProxy {
public void before() {
System.out.println("UserProxy.before()...前置通知");
}
}
在 spring 配置文件中创建两个类对象
在 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 https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 1. 创建两个类的对象 -->
<bean id="user" class="com.atguigu.spring5.aop.xml.User"></bean>
<bean id="userProxy" class="com.atguigu.spring5.aop.xml.UserProxy"></bean>
<!-- 2. 配置aop增强-->
<aop:config>
<!--配置切入点-->
<aop:pointcut id="pointcutAddMethod" expression="execution(* com.atguigu.spring5.aop.xml.User.add(..))"/>
<!--配置切面: ref引用代理类-->
<aop:aspect ref="userProxy">
<!--配置增强作用在具体的方法上,这里是UserProxy类上的before方法作用在切入点add()方法上-->
<aop:before method="before" pointcut-ref="pointcutAddMethod"/>
</aop:aspect>
</aop:config>
</beans>
测试:
package com.atguigu.sprint5;
import com.atguigu.spring5.aop.xml.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAop {
@Test
public void testAopXML() {
ApplicationContext context = new ClassPathXmlApplicationContext("aop.xml");
User user = context.getBean("user", User.class);
user.add();
}
}