Spring AOP拦截-三种方式实现自动代理详解

这里的自动代理,我讲的是自动代理bean对象,其实就是在xml中让我们不用配置代理工厂,也就是不用配置class为org.springframework.aop.framework.ProxyFactoryBean的bean。

总结了一下自己目前所学的知识。

发现有三种方式实现自动代理

用Spring一个自动代理类DefaultAdvisorAutoProxyCreator:

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" data-filtered="filtered"></bean>

例如:

原来不用自动代理的配置文件如下:

<!--?xml version="1.0" encoding="UTF-8"?-->
<beans xmlns="https://www.springframework.org/schema/beans" xmlns:context="https://www.springframework.org/schema/context" xmlns:tx="https://www.springframework.org/schema/tx" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-4.3.xsd
        https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context-4.3.xsd
        https://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
  <!-- 代理前原对象 -->
  <bean class="cn.hncu.xmlImpl.Person" id="person"></bean>
  <!-- 切面 = 切点+通知 -->
  <bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="advisor">
    <!-- 切点 -->
    <property name="patterns">
      <list>
        <value>.*run.*</value>
      </list>
    </property>
    <!-- 通知-由我们写,实际代理动作 -->
    <property name="advice">
      <bean class="cn.hncu.xmlImpl.AroundAdvice" id="advice"></bean>
    </property>
  </bean>
  <!-- 代理工厂 -->
  <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="personProxied">
    <!-- 放入原型对象 -->
    <property name="target" ref="person"></property>
    <!-- 放入切面 -->
    <property name="interceptorNames">
      <list>
        <value>advisor</value>
      </list>
    </property>
  </bean>
</beans>

现在改用自动代理,如下配置:

<beans ...="">
<!-- 代理前原对象 -->
  <bean class="cn.hncu.xmlImpl.Person" id="person"></bean>
  <!-- 切面 = 切点+通知 -->
  <bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="advisor">
    <!-- 切点 -->
    <property name="patterns">
      <list>
        <value>.*run.*</value>
      </list>
    </property>
    <!-- 通知-由我们写,实际代理动作 -->
    <property name="advice">
      <bean class="cn.hncu.xmlImpl.AroundAdvice" id="advice"></bean>
    </property>
  </bean>

  <!-- 自动代理 -->
  <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
</beans>

测试方法

@Test//自动代理
  public void demo4(){
    ApplicationContext ctx = new ClassPathXmlApplicationContext("cn/hncu/xmlImpl/4.xml");
    //我们直接在这里获取Person对象就可以了,因为在最开始xml文件newPerson对象后,Spring就已经帮我们代理了!
    Person p =ctx.getBean(Person.class);
    p.run();
    p.say();
  }

相对于前面,也就是把代理工厂部分换成自动代理了。

演示结果:

自己写一个自动代理底层实现:

我们也可以写一个类,来实现DefaultAdvisorAutoProxyCreator自动代理的功能!

首先,我们需要实现一个接口,也就是BeanPostProcessor接口。

BeanPostProcessor接口作用是:如果我们需要在Spring容器完成Bean的实例化、配置和其他的初始化前后添加一些自己的逻辑处理,我们就可以定义一个或者多个BeanPostProcessor接口的实现,然后注册到容器中。

而我们想要在原型对象bean被创建之后就代理了,就必须在原来的容器中拿到原来的原型对象,需要拿到原来spring容器中的切面对象,这个时候,我们就需要原来的容器,这个时候就需要另一个接口,也就是ApplicationContextAware接口!

通过这2个接口,我们就可以实现自动代理了。

package cn.hncu.xmlImpl;
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class MyAutoProxy implements BeanPostProcessor,ApplicationContextAware{
  private ApplicationContext applicationContext=null;
  //bean创建之前调用
  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName)
      throws BeansException {
    return bean;//在这里,我们直接放行
  }
  //bean创建之后调用
  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName)
      throws BeansException {
    ProxyFactoryBean factory = new ProxyFactoryBean();
    //把原型对象放入代理工厂
    factory.setTarget(bean);
    //在这里
    Advisor adv = applicationContext.getBean(Advisor.class);
    factory.addAdvisor(adv);
    //返回被代理后的对象
    return factory.getObject();
  }
  //拿到原来的spring中的容器
  @Override
  public void setApplicationContext(ApplicationContext applicationContext)
      throws BeansException {
    this.applicationContext=applicationContext;
  }
}

5.xml

<beans...>
<!-- 代理前原对象 -->
  <bean class="cn.hncu.xmlImpl.Person" id="person"></bean>

  <!-- 切面 = 切点+通知 -->
  <bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="advisor">
    <!-- 切点 -->
    <property name="patterns">
      <list>
        <value>.*run.*</value>
      </list>
    </property>
    <!-- 通知-由我们写,实际代理动作 -->
    <property name="advice">
      <bean class="cn.hncu.xmlImpl.AroundAdvice" id="advice"></bean>
    </property>
  </bean>

  <!-- 自己写的自动代理 -->
  <bean class="cn.hncu.xmlImpl.MyAutoProxy"></bean>
</beans...>

测试方法:

@Test//自己实现的自动代理
  public void demo5(){
    ApplicationContext ctx = new ClassPathXmlApplicationContext("cn/hncu/xmlImpl/5.xml");
    Person p =ctx.getBean(Person.class);
    p.run();
    p.say();
  }

测试结果就不上图了,和前面是一样的。

其实很多时候,我们如果自己去练一下底层,对上层的框架更好理解。

还有一种方法。

使用aop标签配自动代理

需要在beans加一个命名空间

xmlns:aop=https://www.springframework.org/schema/aop

还需要配xsi:schemaLocation,为aop加一个网络地址。

https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop-4.3.xsd

我们需要一个aspectjweaver-jar包:

xml配置文件:

<!--?xml version="1.0" encoding="UTF-8"?-->
<beans xmlns="https://www.springframework.org/schema/beans" xmlns:aop="https://www.springframework.org/schema/aop" xmlns:context="https://www.springframework.org/schema/context" xmlns:tx="https://www.springframework.org/schema/tx" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-4.3.xsd
        https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context-4.3.xsd
        https://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx-4.3.xsd
        https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop-4.3.xsd ">
  <!-- 利用sop标签实现自动代理 -->
  </aop:aspectj-autoproxy>

  <!-- 代理前原对象 -->
  <bean class="cn.hncu.xmlImpl.Person" id="person"></bean>

  <!-- 切面 = 切点+通知 -->
  <bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="advisor">
    <!-- 切点 -->
    <property name="patterns">
      <list>
        <value>.*run.*</value>
      </list>
    </property>
    <!-- 通知-由我们写,实际代理动作 -->
    <property name="advice">
      <bean class="cn.hncu.xmlImpl.AroundAdvice" id="advice"></bean>
    </property>
  </bean>

</beans>

测试方法:

@Test//自动代理
  public void demo6(){
    ApplicationContext ctx = new ClassPathXmlApplicationContext("cn/hncu/xmlImpl/6.xml");
    Person p =ctx.getBean(Person.class);
    p.run();
    p.say();
  }

测试结果:

个人觉得能学会使用一种就OK了,不用全部记下来,为了学习,都了解一下就好,别人写出来,能看懂就好。

哈哈,其实底层学好了,自己写的时候,就算不会用Spring的自动代理,自己写出来底层也是蛮好的嘛

总结

以上本文关于Spring AOP拦截-三种方式实现自动代理详解的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:快速理解Java设计模式中的组合模式、Java编程接口调用的作用及代码分享、浅谈Java实体对象的三种状态以及转换关系等,有什么问题可以随时留言,小编会及时回复大家的。感谢朋友们对本站的支持!

(0)

相关推荐

  • 详解Spring MVC拦截器实现session控制

    未登录,不允许访问background文件夹内的页面,那如何判断是否登录呢?background是关键目录,每个操作该目录的人都需要写在日志表中,如何实现呢?拦截器是实现方案之一. (1) 在com.geloin.spring.interceptor包中添加SystemInterceptor,并使其继承HandlerInterceptor /** * * @author geloin */ package com.geloin.spring.interceptor; import java.io

  • SpringMVC配置拦截器实现登录控制的方法

    SpringMVC读取Cookie判断用户是否登录,对每一个action都要进行判断.之前使用jstl标签在页面上判断session如果没有登录就使用如下代码跳转到登录页面. <c:if test="${sessionScope.login == null || sessionScope.login == false}"> <!-- 未登录 --> <c:redirect url="/login"/> </c:if>

  • SpringMVC拦截器实现登录认证

    博客以Demo的形式讲诉拦截器的使用 项目结构如图: 需要的jar:有springMVC配置需要的jar和jstl需要的jar SpringMVC包的作用说明: aopalliance.jar:这个包是AOP联盟的API包,里面包含了针对面向切面的接口.通常spring等其它具备动态织入功能的框架依赖这个jar spring-core.jar:这个jar 文件包含Spring 框架基本的核心工具类.Spring 其它组件要都要使用到这个包里的类,是其它组件的基本核心,当然你也可以在自己的应用系统

  • 使用spring拦截器实现日志管理实例

    使用HandlerInterceptor拦截器,可以拦截请求,实现通用的日志管理操作  一.添加拦截器类 在"src/main/java"代码文件夹的"org.xs.demo1"的包下新建"LogInterceptor.java"类: package org.xs.demo1; import java.text.SimpleDateFormat; import javax.servlet.http.HttpServletRequest; impo

  • Spring MVC 拦截器实现代码

    拦截器的实现 1.编写拦截器类实现HandlerInterceptor接口: 2.将拦截器注册进springmvc框架中: 3.配置拦截器的拦截规则: 其他实现方法 WebRequestInterceptor接口: 与上一个的区别是参数区别和prehandle的方法没有返回值.没有上一个功能全,因此常用第一个. 拦截器的使用场景 处理所有请求共性问题: 1.乱码问题:用request,response参数去设置编码: 2.解决权限验证问题(是否登陆,取session对象查看): 拦截器与过滤器的

  • Spring MVC--拦截器实现和用户登陆例子

    1.拦截器 SpringMvc中的拦截器实现了HandlerInterceptor接口,通常使用与身份认证,授权和校验,模板视图,统一处理等: public class HanderInterceptor1 implements HandlerInterceptor { @Override public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception ar

  • Spring AOP拦截-三种方式实现自动代理详解

    这里的自动代理,我讲的是自动代理bean对象,其实就是在xml中让我们不用配置代理工厂,也就是不用配置class为org.springframework.aop.framework.ProxyFactoryBean的bean. 总结了一下自己目前所学的知识. 发现有三种方式实现自动代理 用Spring一个自动代理类DefaultAdvisorAutoProxyCreator: <bean class="org.springframework.aop.framework.autoproxy.

  • Spring深入讲解实现AOP的三种方式

    [重点] 使用AOP织入 需要导入一个依赖包 <dependencies> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.9.1</version> </dependency> </dependencies> 方式一:使用原生Spring AP

  • 对Python中创建进程的两种方式以及进程池详解

    在Python中创建进程有两种方式,第一种是: from multiprocessing import Process import time def test(): while True: print('---test---') time.sleep(1) if __name__ == '__main__': p=Process(target=test) p.start() while True: print('---main---') time.sleep(1) 上面这段代码是在window

  • vue父子组件动态传值的几种方式及注意问题详解

    1.vue父组件向子组件动态传值的两种方法 在一些项目需求中需要父组件向子组件动态传值,比如我这里的需求是,父组件动态通过axios获取返回的图片url数组然后传给子组件,上传图片的子组件拿到该数组后进行遍历并展示图片,因为有时候获取到的会是空,所以这里要考虑到动态获取. 方法有两种, vue父组件向子组件动态传值方法一: props传值,这里注意一个问题,传过来的值需要用watch监听并赋值,否则这里获取到的是空数组 父组件: <uploadImg :width="200" :

  • java实现图的邻接表存储结构的两种方式及实例应用详解

    前言 本篇来谈一谈图的邻接表实现的两种方式,首先我们明确一点"学会图的邻接表实现的关键点在于":你所建立的图的邻接表的对象是什么! 首先我们看一下<算法导论>中关于图的邻接表的定义: 图G=(V,E)的邻接表表示有一个包含 |V| 个列表的数组Adj所组成,其中每个列表对应于V中的一个顶点,对于每一个u∈V,邻接表Adj[u]包含所有满足条件(u,v)∈E的顶点v,亦即,Adj[u]包含图G中所有和顶点u相邻的顶点.(或者他也可能指向这些顶点的指针),每个邻接表中的顶点一般

  • Java三种IO模型原理实例详解

    Java中IO的模型分为三种,同步阻塞的BIO.同步非阻塞的NIO.异步非阻塞的AIO. BIO[同步阻塞] 在JDK1.4出来之前,我们建立网络连接的时候采用BIO模式,需要先在服务端启动一个ServerSocket,然后在客户端启动Socket来对服务端进行通信,默认情况下服务端需要对每个请求建立一堆线程等待请求,而客户端发送请求后,先咨询服务端是否有线程相应,如果没有则会一直等待或者遭到拒绝请求,如果有的话,客户端会线程会等待请求结束后才继续执行. NIO[同步非阻塞] NIO本身是基于事

  • get post jsonp三种数据交互形式实例详解

    一.get请求 1.引入 vue.js 和 vue-resource.js , 准备一个按钮 <input type="button" value="按钮" @click="get()"/> //点击按钮请求数据函数get() 2.准备一个txt文件 welcome vue 3.编写js代码 <script> window.onload=function(){ new Vue({ el:'body', //主体为body,

  • ASP.NET 中 Button、LinkButton和ImageButton 三种控件的使用详解

    ASP.NET Framework包含三个用于向服务器端提交表单的控件:Button.LinkButton和ImageButton.这三个控件拥有同样的功能,但每种控件的外观界面不同. 本文就带着大家学习如何在页面中使用这三种控件.然后,学习如何关联客户端脚本和服务器端Button控件,以及如何使用Button控件把一个表单传到不是当前页的页面.最后,学习如何处理Button控件的Command事件. 一.使用Button控件 Button控件用来向服务器端提交表单的按钮.例如,代码清单1中的页

  • webstorm中配置Eslint的两种方式及差异比较详解

    写在前面 这两种方式的配置基本相同,都是配一下node地址,Eslint执行文件的地址,Eslint的配置文件(就是.eslintrc)等,而且网上很方便就可以搜索到,就不多说了. 之所以要比较一下两者的差异,就是因为对于没有配置过的同学来说,看了诸如"怎么在webstorm下配置Eslint"的问题下面的回答,既有说用方式1,又有说方式2的,然后这两种方式配置项还差不多(都是在webstorm的一个setting页面里面设置三四个项目,然后勾上enable复选框),就容易混淆. 再加

  • get  post jsonp三种数据交互形式实例详解

    一.get请求 1.引入 vue.js 和 vue-resource.js , 准备一个按钮 <input type="button" value="按钮" @click="get()"/> //点击按钮请求数据函数get() 2.准备一个txt文件 welcome vue 3.编写js代码 <script> window.onload=function(){ new Vue({ el:'body', //主体为body,

随机推荐