一.动态代理
1.创建一个接口
ArithmeticCalculator
package com.atguigu.spring.aop.helloworld; public interface ArithmeticCalculator { int add(int i ,int j); int sub(int i ,int j); int mul(int i ,int j); int div(int i ,int j); }
2.创建接口的实现类
package com.atguigu.spring.aop.helloworld; public class ArithmeticCalculatorImpl implements ArithmeticCalculator { @Override public int add(int i, int j) { int result = i +j; return result; } @Override public int sub(int i, int j) { int result = i - j; return result; } @Override public int mul(int i, int j) { int result = i * j; return result; } @Override public int div(int i, int j) { int result = i / j; return result; } }
3.创建代理类
package com.atguigu.spring.aop.helloworld; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays; public class ArithmeticCalculatorLoggingProxy { //要代理的对象 private ArithmeticCalculator target; public ArithmeticCalculatorLoggingProxy(ArithmeticCalculator target) { this.target = target; } public ArithmeticCalculator getLoggingProxy(){ ArithmeticCalculator proxy = null; //代理对象由哪一个类加载器负责加载 ClassLoader loader = target.getClass().getClassLoader(); //代理对象的类型,即其中有哪些方法 Class[] interfaces = new Class[]{ArithmeticCalculator.class}; //当调用代理对象其中的方法时,该执行的代码 InvocationHandler h = new InvocationHandler() { /** * proxy:正在返回的那个代理对象,一般情况下,在invoke方法中都不使用该对象 * method:正在被调用的方法 * args:调用方法时,传入的参数 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); //日志 System.out.println("【before】The method" + method + "begins with "+Arrays.asList(args)); //执行方法 Object result = null; try { //前置通知 result = method.invoke(target, args); //返回通知 } catch (Exception e) { e.printStackTrace(); //异常通知,可以访问到方法出现的异常 } //后置通知 因为方法可能会抛异常,所以访问不到方法的返回值 //日志 System.out.println("【ends】The method" + method + "ends with "+ result); return result; } }; proxy = (ArithmeticCalculator)Proxy.newProxyInstance(loader, interfaces, h); return proxy; } }
4.测试类
package com.atguigu.spring.aop.helloworld; public class Main { public static void main(String[] args) { ArithmeticCalculator target = new ArithmeticCalculatorImpl(); ArithmeticCalculator proxy = new ArithmeticCalculatorLoggingProxy(target).getLoggingProxy(); int result = proxy.add(2, 3); //System.out.println("-->"+result); } }
5.配置文件
<?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:aop="http://www.springframework.org/schema/aop" 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/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- 自动扫描的包 --> <context:component-scan base-package="com.atguigu.spring.aop"></context:component-scan> <!-- 使 AspectJ 的注解起作用 ,自动为匹配的类生成代理对象--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
二,Spring AOP
1.定义接口
package com.atguigu.spring.aop.impl; public interface ArithmeticCalculator { int add(int i ,int j); int sub(int i ,int j); int mul(int i ,int j); int div(int i ,int j); }
2.创建接口的实现类
package com.atguigu.spring.aop.impl; import org.springframework.stereotype.Component; @Component public class ArithmeticCalculatorImpl implements ArithmeticCalculator { @Override public int add(int i, int j) { int result = i +j; return result; } @Override public int sub(int i, int j) { int result = i - j; return result; } @Override public int mul(int i, int j) { int result = i * j; return result; } @Override public int div(int i, int j) { int result = i / j; return result; } }
3.创建切面
package com.atguigu.spring.aop.impl; import java.util.Arrays; import java.util.List; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; //把这个类生命为一个切面:需要先把该类放到IOC容器中,在声明为一个切面 @Component @Aspect public class LoggingAspect { //声明该方法是一个前置通知:在目标方法开始之前执行 @Before(value = "execution(public int com.atguigu.spring.aop.impl.ArithmeticCalculator.*(int,int))") public void beforeMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); List<Object> args = Arrays.asList(joinPoint.getArgs()); System.out.println("The method"+methodName+" begins. with.."+args); } //后置通知:在目标方法执行后(无论是否发生异常),执行的通知 //在后置通知中还不能访问目标方法执行的结果 @After(value = "execution(* com.atguigu.spring.aop.impl.*.*(int,int))") public void afterMethod(JoinPoint joinPoint){ String methodName = joinPoint.getSignature().getName(); System.out.println("后置通知---The method "+methodName+" ends "); } /** * 在方法正常结束之后执行的代码 * 返回通知 是可以返回目标方法执行的结果 * @param joinPoint */ @AfterReturning(value = "execution(* com.atguigu.spring.aop.impl.*.*(int,int))",returning = "result") public void afterReturning(JoinPoint joinPoint,Object result){ String methodName = joinPoint.getSignature().getName(); System.out.println("返回通知---The method " + methodName + " ends with " + result); } /** * 在目标方法出现异常时会执行的代码 * 可以访问到异常对象,且可以指定在出现特定异常时在执行的代码 * 例如:测试的时候使用100/0 会报java.lang.ArithmeticException: / by zero 异常, * 但在接受的时候使用的是NullPointerException,(afterThrowing(JoinPoint joinPoint,NullPointerException ex)) * 那么将不会执行方法 * @param joinPoint * @param ex */ @AfterThrowing(value = "execution(* com.atguigu.spring.aop.impl.*.*(int,int))", throwing = "ex") public void afterThrowing(JoinPoint joinPoint,Exception ex){ String methodName = joinPoint.getSignature().getName(); System.out.println("异常通知---The method " + methodName + " occurs exception with " + ex); } /** * 环绕通知需要携带ProceedingJoinPoint类型的参数 * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法 * 且环绕通知必须有返回值,返回值即为目标方法的返回值。 * @param pjd */ @Around("execution(* com.atguigu.spring.aop.impl.*.*(int,int))") public Object aroundMethod(ProceedingJoinPoint pjd){ Object result = null; String methodName = pjd.getSignature().getName(); //执行目标方法 try { //前置通知 System.out.println("The method " + methodName + "begins with" + Arrays.asList(pjd.getArgs())); //执行目标方法 result = pjd.proceed(); //返回通知 System.out.println("The method " + methodName + "ends with" +result); } catch (Throwable e) { //异常通知 System.out.println("异常通知---The method " + methodName + " occurs exception with " + e); e.printStackTrace(); } //后置通知 System.out.println("The method " + methodName + "ends"); return result; } }
4.测试类
package com.atguigu.spring.aop.impl; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { //1.创建Spring的IOC容器 ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml"); //2.从IOC容器中获取Bean的实例 ArithmeticCalculator arith = app.getBean(ArithmeticCalculator.class); //3.使用Bean int result = arith.add(3, 6); System.out.println("result:" + result); result = arith.div(100, 0); System.out.println("result:" + result); } }
5.配置文件
<?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:aop="http://www.springframework.org/schema/aop" 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/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- 自动扫描的包 --> <context:component-scan base-package="com.atguigu.spring.aop"></context:component-scan> <!-- 使 AspectJ 的注解起作用 ,自动为匹配的类生成代理对象--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
6.使用的jar文件: