zoukankan      html  css  js  c++  java
  • Spring学习十五----------Spring AOP API的Pointcut、advice及 ProxyFactoryBean相关内容

    © 版权声明:本文为博主原创文章,转载请注明出处

    实例:

    1.项目结构

    2.pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    
    	<modelVersion>4.0.0</modelVersion>
    	
    	<groupId>org.spring</groupId>
    	<artifactId>Spring-AOP-API</artifactId>
    	<packaging>war</packaging>
    	<version>0.0.1-SNAPSHOT</version>
    	<name>Spring-AOP-API Maven Webapp</name>
    	<url>http://maven.apache.org</url>
    	
    	<properties>
    		<spring.version>4.3.8.RELEASE</spring.version>
    	</properties>
    	
    	<dependencies>
    		<!-- junit -->
    		<dependency>
    			<groupId>junit</groupId>
    			<artifactId>junit</artifactId>
    			<version>4.12</version>
    			<scope>test</scope>
    		</dependency>
    		<!-- Spring Core -->
    		<dependency>
    		    <groupId>org.springframework</groupId>
    		    <artifactId>spring-core</artifactId>
    		    <version>${spring.version}</version>
    		</dependency>
    		<dependency>
    		    <groupId>org.springframework</groupId>
    		    <artifactId>spring-beans</artifactId>
    		    <version>${spring.version}</version>
    		</dependency>
    		<dependency>
    		    <groupId>org.springframework</groupId>
    		    <artifactId>spring-context</artifactId>
    		    <version>${spring.version}</version>
    		</dependency>
    	</dependencies>
    	
    	<build>
    		<finalName>Spring-AOP-API</finalName>
    	</build>
    </project>
    

    3.BizLogic.java

    package org.spring.aop.api;
    
    public interface BizLogic {
    
    	String save();
    	
    	String saveEx();
    	
    }
    

    4.BizLogicImpl.java

    package org.spring.aop.api;
    
    public class BizLogicImpl implements BizLogic {
    
    	public String save() {
    		
    		System.out.println("BizLogicImpl:BizLogicImpl save.");
    		return "BizLogicImpl save";
    		
    	}
    	
    	public String saveEx() {
    		
    		System.out.println("BizLogicImpl:BizLogicImpl save.");
    		throw new RuntimeException();
    		
    	}
    
    }
    

    5.CustomBeforeAdvice

    package org.spring.aop.api;
    
    import java.lang.reflect.Method;
    
    import org.springframework.aop.MethodBeforeAdvice;
    
    public class CustomBeforeAdvice implements MethodBeforeAdvice {
    
    	public void before(Method method, Object[] args, Object target) throws Throwable {
    		
    		System.out.println("CustomBeforeAdvice:" + method.getName() + "		" +
    				target.getClass().getName());
    
    	}
    
    }
    

    6.CustomAfterReturnAdvice.java

    package org.spring.aop.api;
    
    import java.lang.reflect.Method;
    
    import org.springframework.aop.AfterReturningAdvice;
    
    public class CustomAfterReturnAdvice implements AfterReturningAdvice {
    
    	public void afterReturning(Object returnValue, Method method, Object[] args, Object target) 
    			throws Throwable {
    		
    		System.out.println("CustomAfterReturnAdvice:" + method.getName() + "		" 
    				+ target.getClass().getName() + "		" + returnValue);
    
    	}
    
    }
    

    7.CustomThrowsAdvice.java

    package org.spring.aop.api;
    
    import java.lang.reflect.Method;
    
    import org.springframework.aop.ThrowsAdvice;
    
    public class CustomThrowsAdvice implements ThrowsAdvice {
    
    	public void afterThrowing(Exception ex) throws Throwable {
    		
    		System.out.println("CustomThrowsAdvice afterThrowing 1");
    		
    	}
    	
    	public void afterThrowing(Method method, Object[] args, Object target, Exception ex) 
    			throws Throwable {
    		
    		System.out.println("CustomThrowsAdvice afterThrowing 2:" + method.getName() + "		"
    				+ target.getClass().getName());
    		
    	}
    	
    }
    

    8.CustomMethodInterceptor.java

    package org.spring.aop.api;
    
    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;
    
    public class CustomMethodInterceptor implements MethodInterceptor {
    
    	public Object invoke(MethodInvocation invocation) throws Throwable {
    		
    		System.out.println("CustomMethodInterceptor 1:" + invocation.getMethod().getName()
    				+ "		" + invocation.getStaticPart().getClass().getName());
    		Object obj = invocation.proceed();
    		System.out.println("CustomMethodInterceptor 2:" + obj);
    		return obj;
    		
    	}
    
    }

    9.Lockable.java

    package org.spring.aop.api.introduction;
    
    /**
     * 接口
     *
     */
    public interface Lockable {
    
    	void lock();
    	
    	void unlock();
    	
    	boolean locked();
    	
    }
    

    10.LockMixin.java

    package org.spring.aop.api.introduction;
    
    import org.aopalliance.intercept.MethodInvocation;
    import org.springframework.aop.support.DelegatingIntroductionInterceptor;
    
    /**
     * 实现类
     *
     */
    public class LockMixin extends DelegatingIntroductionInterceptor implements Lockable {
    
    	private static final long serialVersionUID = 1L;
    	
    	private boolean locked;
    
    	public void lock() {
    	
    		this.locked = true;
    
    	}
    
    	public void unlock() {
    
    		this.locked = false;
    		
    	}
    
    	public boolean locked() {
    		
    		return this.locked;
    		
    	}
    	
    	/**
    	 * 被锁定后不能使用setter方法改变值
    	 */
    	@Override
    	public Object invoke(MethodInvocation invocation) throws Throwable {
    		
    		if(locked && invocation.getMethod().getName().indexOf("set") == 0){
    			throw new RuntimeException();
    		}
    		return super.invoke(invocation);
    		
    	}
    
    }
    

    11.LockMixinAdvisor.java

    package org.spring.aop.api.introduction;
    
    import org.springframework.aop.support.DefaultIntroductionAdvisor;
    
    /**
     * Introduction,在不改变代码的情况下,添加一个父类
     *
     */
    public class LockMixinAdvisor extends DefaultIntroductionAdvisor {
    
    	private static final long serialVersionUID = 1L;
    
    	public LockMixinAdvisor() {
    		
    		super(new LockMixin(), Lockable.class);
    		
    	}
    
    }
    

    12.Spring-aop-api.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
            
    	<!-- Before advice
    			-一个简单的通知类型
    			-只是进方法之前被调用,不需要MethodInvocation对象
    			-前置通知可以在连接点执行之前插入自定义行为,但不能改变返回值
    	 -->
    	<bean id="customBeforeAdvice" class="org.spring.aop.api.CustomBeforeAdvice"/>
        
        <!-- Throws advice
        		-如果连接点抛出异常,throws advice在连接点返回后被调用
        		-如果throws-advice的方法抛出异常,那么它将覆盖原有异常
        		-接口org.springframework.aop.ThrowsAdvice不包含任何方法,仅仅是一个声明,实现类需要实现类似下面的方法
        		-void afterThrowing([Method, args, target], ThrowableSubclass)
         -->
        <bean id="customThrowsAdvice" class="org.spring.aop.api.CustomThrowsAdvice"/>
        
        <!-- After Returning advice 
        		-后置通知必须实现org.springframework.aop.AfterReturningAdvice几口
        		-可以访问返回值(但不能进行修改)、被调用的方法、方法的参数和目标
        		-如果抛出异常,将会抛出拦截器链,替代返回值
         -->
    	<bean id="customAfterReturnAdvice" class="org.spring.aop.api.CustomAfterReturnAdvice"/>
        
        <!-- Interception around advice
        		-Spring的切入点模型使得切入点可以独立与advice重用,以针对不同的advice可以使用相同的切入点
         -->
    	<bean id="customMethodInterceptor" class="org.spring.aop.api.CustomMethodInterceptor"/>
         
    	<!-- Introduction advice
    			-Spring把引入通知作为一种特殊的拦截通知
    			-需要IntroductionAdvisor和IntroductionInterceptor
    			-仅适用于类,不能和任何切入点一起使用
    			-实例:如果调用lock()方法,希望所有的setter方法抛出LockedException异常。
    			-代码:Lockalbe.java	LockMixin.java	LockMixinAdvisor.java
    	-->
    	<!-- Advisor API
    			-Advisor是仅包含一个切入点表达式关联的单个通知的方面
    			-除了introductions,advisor可以用于任何通知
    			-org.springframework.aop.support.DefaultIntroductionAdvisor是最常用的advisor类,
    				它可以与MethodInterceptor,BeforeAdvice或者ThrowsAdvice一起使用
    			-它可以混合在Spring同一个AOP代理的advisor和advice
    	 -->
    	
        <!-- 当使用方式三时,屏蔽该bean的定义 -->
        <!-- <bean id="bizLogicImplTarget" class="org.spring.aop.api.BizLogicImpl"/> -->
    	
    	<!-- ###########################方式一:使用pointcutBean开始############################# -->
    	<!-- 根据方法名匹配切入点pointcut -->
    	<!-- <bean id="pointcutBean" class="org.springframework.aop.support.NameMatchMethodPointcut">
    		<property name="mappedNames">成员变量,匹配的方法名集合
    			<list>
    				<value>sa*</value>
    			</list>
    		</property>
    	</bean>
        
        <bean id="defaultAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
    		<property name="advice" ref="customBeforeAdvice"/>接入点通知,若非接入点,则该通知不生效
    		<property name="pointcut" ref="pointcutBean"/>接入点
        </bean> -->
        
        <!-- ProxyFactoryBean
        		-创建Spring AOP代理的基本方法是使用org.springframework.aop.framework.ProxyFactoryBean
        		-这可以完全控制切入点和通知(advice)以及它们的顺序
        		-ProxyFactoryBean实现里getObject()方法创建一个AOP代理包装一个目标对象
        		-使用ProxyFactoryBean或者其它IOC相关类来创建AOP代理的最重要的好处是通知和切入点也可以由IOC来管理
        		-被代理类没有实现任何接口,使用CGLIB代理,否则JDK代理
        		-通过设置proxyTargetClass为true,可强制使用CGLIB
        		-如果目标类实现了一个(或者多个)接口,那么创建代理的类型将依赖ProxyFactoryBean的配置
        		-如果ProxyFactoryBean的proxyInterfaces属性设置为一个或多个全限定接口名,基于JDK的代理将被创建
        		-如果ProxyFactoryBean的proxyInterfaces属性没有被设置,但是目标类实现了一个(或者更多)接口,那么proxyInterfaces
        			将自动检测到这个目标类已经实现了至少一个接口,创建一个基于JDK的代理
         -->
        <!-- <bean id="bizLogicImpl" class="org.springframework.aop.framework.ProxyFactoryBean">
        	<property name="target">为该类创建代理,由ProxyFactoryBean自己去判断是否实现了接口
        		<ref bean="bizLogicImplTarget"/>
        	</property>
        	<property name="interceptorNames">执行该代理的时候执行的interceptor
        		<list>
        			<value>defaultAdvisor</value>
        			<value>customAfterReturnAdvice</value>
        			<value>customMethodInterceptor</value>
        			<value>customThrowsAdvice</value>
        		</list>
        	</property>
        </bean> -->
        <!-- ###############################方式一结束######################################### -->
        <!-- ############################方式二:使用pointcutBean开始############################ -->
        <!-- <bean id="bizLogicImpl" class="org.springframework.aop.framework.ProxyFactoryBean">
        	<property name="proxyInterfaces">直接指定接口
        		<value>org.spring.aop.api.BizLogic</value>
        	</property>
        	<property name="target">为该类创建代理,因为直接指定了接口,所以肯定是使用JDK代理
        		<ref bean="bizLogicImplTarget"/>
        	</property>
        	<property name="interceptorNames">执行该代理的时候执行的interceptor
        		<list>
        			<value>customBeforeAdvice</value>
        			<value>customAfterReturnAdvice</value>
        			<value>customMethodInterceptor</value>
        			<value>customThrowsAdvice</value>
        		</list>
        	</property>
        </bean> -->
        <!-- ###############################方式二结束######################################### -->
        <!-- ##############################方式三:使用匿名内部Bean############################### -->
        <bean id="bizLogicImpl" class="org.springframework.aop.framework.ProxyFactoryBean">
        	<property name="proxyInterfaces"><!-- 直接指定接口 -->
        		<value>org.spring.aop.api.BizLogic</value>
        	</property>
        	<property name="target"><!-- 上面可以直接使用bean id获取bean对象,此时该bean对象没有被代理,配置的advice不会被执行 -->
        		<bean class="org.spring.aop.api.BizLogicImpl"/>
        	</property>
        	<property name="interceptorNames"><!-- 执行该代理的时候执行的interceptor -->
        		<list>
        			<value>customBeforeAdvice</value>
        			<value>customAfterReturnAdvice</value>
        			<value>customMethodInterceptor</value>
        			<value>customThrowsAdvice</value>
        		</list>
        		<!-- 使用global advisors
        				-用*做通配,匹配所有拦截器加入通知链
        			  此处只会执行customMethodInterceptor,因为只有该advice实现了Interceptor接口
        		 -->
        		 <!-- <list>
        		 	<value>custom*</value>
        		 </list> -->
        	</property>
        </bean>
        <!-- ###############################方式三结束######################################### -->
        <!-- ##############################方式四:简化的proxy定义############################### -->
        <!-- 简化的proxy定义
        		-使用父子bean定义以及内部bean定义,可能会带来更清洁和更简洁的代理定义
         -->
        <!-- <bean id="baseProxyBean" class="org.springframework.aop.framework.ProxyFactoryBean"
        	lazy-init="true" abstract="true"/>
        	
        <bean id="bizLogicImpl" parent="baseProxyBean">
        	<property name="proxyInterfaces">直接指定接口
        		<value>org.spring.aop.api.BizLogic</value>
        	</property>
        	<property name="target">上面可以直接使用bean id获取bean对象,此时该bean对象没有被代理,配置的advice不会被执行
        		<bean class="org.spring.aop.api.BizLogicImpl"/>
        	</property>
        	<property name="interceptorNames">执行该代理的时候执行的interceptor
        		<list>
        			<value>customBeforeAdvice</value>
        			<value>customAfterReturnAdvice</value>
        			<value>customMethodInterceptor</value>
        			<value>customThrowsAdvice</value>
        		</list>
        	</property>
        </bean> -->
        <!-- ###############################方式四结束######################################### -->
        
    </beans>

    13.TestBase.java

    package org.spring.aop.api.test;
    
    import org.junit.After;
    import org.junit.Before;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import org.springframework.util.StringUtils;
    
    public class TestBase {
    
    	private ClassPathXmlApplicationContext context;
    	private String springXmlPath;
    	
    	/**
    	 * 无参构造器
    	 */
    	public TestBase() {
    		
    	}
    
    	/**
    	 * 含参构造器,初始化spring配置文件路径
    	 * 
    	 * @param springXmlPath
    	 * 						spring配置文件路径
    	 */
    	public TestBase(String springXmlPath) {
    		
    		this.springXmlPath = springXmlPath;
    		
    	}
    	
    	/**
    	 * 初始化spring配置文件并加载到IOC容器中
    	 */
    	@Before
    	public void before() {
    		
    		if(StringUtils.isEmpty(springXmlPath)) {
    			springXmlPath = "classpath:spring-*.xml";
    		}
    		context = new ClassPathXmlApplicationContext(springXmlPath.split("[,\s]+"));
    		context.start();
    		
    	}
    	
    	/**
    	 * 销毁IOC容器
    	 */
    	@After
    	public void after() {
    		
    		if(context != null){
    			context.destroy();
    		}
    		
    	}
    	
    	/**
    	 * 根据bean ID获取bean对象
    	 * 
    	 * @param beanId
    	 * 					bean ID
    	 * @return
    	 */
    	public Object getBean(String beanId) {
    		
    		return context.getBean(beanId);
    		
    	}
    	
    }
    

    14.TestSpringAOPAPI.java

    package org.spring.aop.api.test;
    
    import org.junit.Test;
    import org.spring.aop.api.BizLogic;
    
    public class TestSpringAOPAPI extends TestBase {
    
    	/**
    	 * 通过构造器初始化spring配置文件
    	 */
    	public TestSpringAOPAPI() {
    		
    		super("classpath:spring-aop-api.xml");
    		
    	}
    	
    	/**
    	 * 测试正常方法
    	 */
    	@Test
    	public void testSave() {
    		
    		BizLogic logic = (BizLogic) super.getBean("bizLogicImpl");
    		logic.save();
    		
    	}
    	
    	/**
    	 * 测试存在异常的方法
    	 */
    	@Test
    	public void testsaveEx() {
    		
    		BizLogic logic = (BizLogic) super.getBean("bizLogicImpl");
    		logic.saveEx();
    		
    	}
    
    }

    15.效果预览

      15.1 执行testSave方法

      15.2 执行testsaveEx方法

    说明:其他几种方式已在spring-aop-api.xml中注明,可自行测试。

    参考:http://www.imooc.com/video/4597

         http://www.imooc.com/video/4598

       http://www.imooc.com/video/4599

  • 相关阅读:
    ubuntu LAMP的安装
    windows中安装liunx虚拟机
    jQuery Responsive OneByOne Slider Plugin
    轮播图收集
    移动端图片延迟加载插件
    图片幻灯插件
    小tip: base64:URL背景图片与web页面性能优化
    基于HTML5的可预览多图片Ajax上传
    字体平滑解决方案
    webstorm scss编译css配置
  • 原文地址:https://www.cnblogs.com/jinjiyese153/p/6763602.html
Copyright © 2011-2022 走看看