• spring实现AOP


    什么是动态代理

    动态代理利用Java的反射技术(Java Reflection)生成字节码,在运行时创建一个实现某些给定接口的新类(也称"动态代理类")及其实例。

    在基于JDK的动态代理的实现中有两个重要的类:InvocationHandler, Proxy

    • InvocationHandler
      是代理实例的调用处理程序实现的接口。每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法。
    • Proxy
      JDK中动态生成代理类的工具类

    一个动态代理的示例:

    定义一个接口(基于JDK的动态代理只能使用接口)

    1. public interface ISubject {
    2.     void hello(String param);
    3. }

    为接口定义实现类

    1. public class SubjectImpl implements ISubject {
    2.     @Override
    3.     public void hello(String param) {
    4.         System.out.println("hello  " + param);
    5.     }
    6. }

    实现一个代理类:

    1. public class JDKProxy implements InvocationHandler {
    2.     private Object target;
    3.     public JDKProxy(Object target) {
    4.         this.target = target;
    5.     }
    6.     //创建代理
    7.     public Object newProxy() {
    8.      return (ISubject)Proxy.newProxyInstance(
    9.              target.getClass().getClassLoader(),
    10.              target.getClass().getInterfaces(),
    11.              this);
    12.     }
    13.     @Override  
    14.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    15.        System.out.println("---------- 在业务方法调用之前可以进行前置增强   ------------");
    16.         //利用反射机制调用方法,invoke为返回值,如果没有返回null
    17.         Object invoke = method.invoke(target, args);
    18.         System.out.println("---------- 在业务方法调用之前可以进行后置增强   ------------");
    19.         return invoke;
    20.     }
    21. }

    编写代理类实际的调用,利用Proxy类创建代理之后的Subject类

    1. public class JDKProxyDemo {
    2.     public static void main(String[] args) {
    3.         ISubject subject = new SubjectImpl();
    4.         JDKProxy subjectProxy = new JDKProxy(subject);
    5.         ISubject proxyInstance = (ISubject)subjectProxy.newProxy();
    6.         proxyInstance.hello("world");
    7.     }
    8.    
    9. }

    运行结果:

    1. ---------- 在业务方法调用之前可以进行前置增强   ------------
    2. hello  world
    3. ---------- 在业务方法调用之前可以进行后置增强   ------------

    1.什么是AOP?

    AOP全称(Aspect Oriented Programming)面向切片编程的简称

    AOP的作用:

    利用AOP对业务逻辑的各个部分进行隔离,降低业务逻辑的耦合性,提高程序的可重用型和开发效率。

    常见的通知

    前置通知 方法执行前调用
    后置通知 方法执行后调用
    返回通知 方法返回后调用
    异常通知 方法出现异常调用
    环绕通知 动态代理、手动推荐方法运行

    连接点(Joinpoint)
    程序能够应用通知的一个“时机”,这些“时机”就是连接点,例如方法调用时、异常抛出时、方法返回后等等。

    切入点(Pointcut)
    通知定义了切面要发生的“故事”,连接点定义了“故事”发生的时机,那么切入点就定义了“故事”发生的地点

    代理(proxy)
    应用通知的对象,详细内容参见设计模式里面的动态代理模式。

    目标(Target)
    即被通知的对象

    适配器(Advisor)
    适配器=通知(Advice)+切入点(Pointcut)

    通知(Advice)
    在某个特定的连接点上执行的动作,同时Advice也是程序代码的具体实现,例如一个实现日志记录的代码(通知有些书上也称为处理)

    效果如下

     

    demo测试类

    1. public static void main(String[] args) {
    2. ApplicationContext cxt= new ClassPathXmlApplicationContext("spring_01.xml");
    3. IBookService biz =(IBookService) cxt.getBean("bookService");
    4. List list = biz.getBooks();
    5. System.out.println(list);
    6. }

    spring的配置文件

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:context="http://www.springframework.org/schema/context"
    5. 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">
    6. <bean id="bookDao" class="com.zking.spring.dao.Bookdao">
    7. bean>
    8. <bean id="bookServiceTarget" class="com.zking.spring.service.BookService">
    9. <property name="bookdao" ref="bookDao">property>
    10. bean>
    11. <bean id="myMethodBeforeAdvice" class="com.zking.spring.aop.MyMethodBeforeAdvice"/>
    12. <bean id="myAfterReturnAdvice" class="com.zking.spring.aop.MyAfterReturnAdvice"/>
    13. <bean id="myMethodInterceptor" class="com.zking.spring.aop.MyMethodInterceptor"/>
    14. <bean id="myThrowsAdvice" class="com.zking.spring.aop.MyThrowsAdvice"/>
    15. <bean id="bookService" class="org.springframework.aop.framework.ProxyFactoryBean">
    16. <property name="target" ref="bookServiceTarget"/>
    17. <property name="interceptorNames">
    18. <list>
    19. <value>myMethodBeforeAdvicevalue>
    20. <value>myAfterReturnAdvicevalue>
    21. <value>myMethodInterceptorvalue>
    22. <value>myThrowsAdvicevalue>
    23. list>
    24. property>
    25. <property name="proxyInterfaces">
    26. <list>
    27. <value>com.zking.spring.service.IBookServicevalue>
    28. list>
    29. property>
    30. bean>
    31. <bean id="myAdisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    32. <property name="patterns">
    33. <list>
    34. <value>.*buyvalue>
    35. list>
    36. property>
    37. <property name="advice">
    38. <ref bean="myAfterReturnAdvice"/>
    39. property>
    40. bean>
    41. <context:component-scan base-package="com.zking.spring"/>
    42. <bean id="propPlaceholder" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    43. <property name="locations">
    44. <list>
    45. <value>classpath:/project.propertiesvalue>
    46. list>
    47. property>
    48. bean>
    49. beans>

    Ibookdao类

    1. public interface IBookdao {
    2. public List getBooks();
    3. }

    bookdaoimp类

    1. @Repository
    2. public class Bookdao implements IBookdao{
    3. @Override
    4. public List getBooks() {
    5. List b=new ArrayList<>();
    6. b.add(new Book("sb"));
    7. b.add(new Book("shabi"));
    8. b.add(new Book("gobi"));
    9. return b;
    10. }
    11. }

     注:@Repository是spring容器中dao层的一个组件,此处通过注解方式配置

    IbookService类

    1. public interface IBookService {
    2. public List getBooks();
    3. // 购书
    4. public boolean buy(String userName, String bookName, Double price);
    5. // 发表书评
    6. public void comment(String userName, String comments);
    7. }

     bookService类

    1. @Service
    2. public class BookService implements IBookService {
    3. /*@Autowired*/
    4. private IBookdao bookdao;
    5. public void setBookdao(IBookdao bookdao) {
    6. this.bookdao = bookdao;
    7. }
    8. @Override
    9. public List getBooks() {
    10. return bookdao.getBooks();
    11. }
    12. @Override
    13. public boolean buy(String userName, String bookName, Double price) {
    14. // 通过控制台的输出方式模拟购书
    15. System.out.println(userName + " buy " + bookName + ", spend " + price);
    16. return true;
    17. }
    18. @Override
    19. public void comment(String userName, String comments) {
    20. System.out.println(userName + " say:" + comments);
    21. }
    22. }

    注:Service是spring容器中service层中的一个组件,此处通过注解方式配置

    前置通知,需要实现MethodBeforeAdvice,前置通知将在目标对象调用前调用,简单打印。

    1. public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
    2. @Override
    3. public void before(Method method, Object[] args, Object target) throws Throwable {
    4. String b=( "[前置通知]: "
    5. + this.getClass() + "."
    6. + method.getName()
    7. + "将被调用,参数为:"
    8. + Arrays.toString(args));
    9. System.out.println(b);
    10. }
    11. }

    后置通知,要实现AfterRetruningAdvice

    1. public class MyAfterReturnAdvice implements AfterReturningAdvice {
    2. @Override
    3. public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
    4. System.out.println("[后置通知]:xxxxxxx");
    5. }
    6. }

     环绕通知,需要实现MethodInterceptor

    1. public class MyMethodInterceptor implements MethodInterceptor {
    2. @Override
    3. public Object invoke(MethodInvocation invocation) throws Throwable {
    4. //获取目标对象
    5. Object target = invocation.getThis();
    6. //获取参数
    7. Object[] args = invocation.getArguments();
    8. //获取方法
    9. Method method = invocation.getMethod();
    10. System.out.println("[环绕通知] 前:将调用"+target.getClass()+"."+method.getName()+"方法,参数为"+ Arrays.toString(args));
    11. //调用目标对象上的方法
    12. Object val = invocation.proceed();
    13. System.out.println("[环绕通知] 前:将调用"+target.getClass()+"."+method.getName()+"方法,参数为"+ val);
    14. return val;
    15. }
    16. }

    异常通知,需要实现ThorwsAdvice

    1. public class MyThrowsAdvice implements ThrowsAdvice {
    2. //以异常类型作为参数,无返回值
    3. public void afterThrowing(PriceException e) {
    4. System.out.println("程序发生了PriceException异常");
    5. }
    6. }

     

     

  • 相关阅读:
    金仓数据库 KingbaseES 插件参考手册 K (1)
    springboot整合redis+lua实现getdel操作保证原子性
    C++零基础教程(抽象类和接口)
    22.在springboot中使用thymeleaf模板(第一个例子)
    智联汽车 — 自动/辅助驾驶技术
    ros2与windows入门教程-编译ROS2包
    批量归一化(标准化)处理
    交易积累-RSI
    还在用纸质表进行设备巡检?
    Python经典面试题
  • 原文地址:https://blog.csdn.net/Bugxiu_fu/article/details/126377945