spring笔记

 spring学习参考: https://www.yiibai.com/spring/

为什么要使用Spring?

Spring主要两个有功能为我们的业务对象管理提供了非常便捷的方法:

  • DI(Dependency Injection,依赖注入)
  • AOP(Aspect Oriented Programming,面向切面编程)

Java Bean

每一个类实现了Bean的规范才可以由Spring来接管,那么Bean的规范是什么呢?

  • 必须是个公有(public)类
  • 有无参构造函数
  • 用公共方法暴露内部成员属性(getter,setter)

实现这样规范的类,被称为Java Bean。即是一种可重用的组件。

DI-依赖注入

简单来说,一个系统中可能会有成千上万个对象。如果要手工维护它们之间的关系,这是不可想象的。我们可以在Spring的XML文件描述它们之间的关系,由Spring自动来注入它们——比如A类的实例需要B类的实例作为参数set进去。

AOP-面向切面编程

就以日志系统为例。在执行某个操作前后都需要输出日志,如果手工加代码,那简直太可怕了。而且等代码庞大起来,也是非常难维护的一种情况。这里就需要面向切面来编程

关于Bean

Bean的生命周期

如你所见,在bean准备就绪之前,bean工厂执行了若干启动步骤。我们对图进行详细描述:

  1. Spring对bean进行实例化;
  2. Spring将值和bean的引用注入到bean对应的属性中;
  3. 如果bean实现了BeanNameAware接口,Spring将bean的ID传递给setBean-Name()方法;
  4. 如果bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入;
  5. 如果bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext()方法,将bean所在的应用上下文的引用传入进来;
  6. 如果bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessBeforeInitialization()方法;
  7. 如果bean实现了InitializingBean接口,Spring将调用它们的after-PropertiesSet()方法。类似地,如果bean使用init-method声明了初始化方法,该方法也会被调用;
  8. 如果bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessAfterInitialization()方法;
  9. 此时,bean已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁;
  10. 如果bean实现了DisposableBean接口,Spring将调用它的destroy()接口方法。同样,如果bean使用destroy-method声明了销毁方法,该方法也会被调用。

Bean的作用域

Spring定义了多种Bean作用域,可以基于这些作用域创建bean,包括:

  • 单例(Singleton):在整个应用中,只创建bean的一个实例。
  • 原型(Prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例。
  • 会话(Session):在Web应用中,为每个会话创建一个bean实例。
  • 请求(Rquest):在Web应用中,为每个请求创建一个bean实例。

声明Bean

以下是声明Bean的注解:

  • @Component 组件,没有明确的角色
  • @Service 在业务逻辑层使用
  • @Repository 在数据访问层使用
  • @Controller 在展现层使用(MVC -> Spring MVC)使用
  • 在这里,可以指定bean的id名:Component(“yourBeanName”)
  • 同时,Spring支持将@Named作为@Component注解的替代方案。两者之间有一些细微的差异,但是在大多数场景中,它们是可以互相替换的

Spring自动装配Beans

<bean id="customer" class="com.yiibai.common.Customer" autowire="byName" />
在Spring中,支持 5 自动装配模式。
  • no – 缺省情况下,自动配置是通过“ref”属性手动设定
  • byName – 根据属性名称自动装配。如果一个bean的名称和其他bean属性的名称是一样的,将会自装配它。
  • byType – 按数据类型自动装配。如果一个bean的数据类型是用其它bean属性的数据类型,兼容并自动装配它。
  • constructor – 在构造函数参数的byType方式。
  • autodetect – 如果找到默认的构造函数,使用“自动装配用构造”; 否则,使用“按类型自动装配”。
<bean id="customer" class="com.yiibai.common.Customer" autowire="byName" />

Spring 装配

通常情况下,您明确装配Bean,这样通过 ref 属性:
<bean id="customer" class="com.yiibai.common.Customer" >
		<property name="address" ref="address" />
	</bean>
	
	<bean id="address" class="com.yiibai.common.Address" >
		    <property name="fulladdress" value="YiLong Road, CA 188" /> </bean>
使用按名称启用自动装配,你不必再声明属性标记。只要在“address” bean是相同于“customer” bean 的“address”属性名称,Spring会自动装配它。
<bean id="customer" class="com.yiibai.common.Customer" autowire="byName" />
<bean id="address" class="com.yiibai.common.Address" >
<property name="fulladdress" value="YiLong Road, CA 188" /> </bean>

构造方法自动装配

Spring装配

通常情况下,你可以通过构造这样自动装配 Bean:
<bean id="developer" class="com.yiibai.common.Developer">
    <constructor-arg>
	<ref bean="language" />
    </constructor-arg>
</bean>
<bean id="language" class="com.yiibai.common.Language" >
	<property name="name" value="Java" />
</bean>
随着自动装配用构造函数启用后,你可以不设置构造器属性。Spring会找到兼容的数据类型,并自动装配它。
<bean id="developer" class="com.yiibai.common.Developer" autowire="constructor" />
<bean id="language" class="com.yiibai.common.Language" >
	<property name="name" value="Java" />
</bean>

 

@Autowired
@Qualifier示例
直接在bean配置文件包含“AutowiredAnnotationBeanPostProcessor”。
<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-2.5.xsd">

<bean 
class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
	
	<bean id="CustomerBean" class="com.yiibai.common.Customer">
		<property name="action" value="buy" />
		<property name="type" value="1" />
	</bean>

	<bean id="PersonBean" class="com.yiibai.common.Person">
		<property name="name" value="yiibai" />
		<property name="address" value="address ABC" />
		<property name="age" value="29" />
	</bean>
	
</beans>
要解决上述问题,需要使用 @Quanlifier 告诉Spring哪些bean应当自动装配。
package com.yiibai.common;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

public class Customer {

	@Autowired
	@Qualifier("personA")
	private Person person;
	//...
}


一般来说, 需要按模块或类别  分割Spring XML bean文件 成多个小文件, 使事情更容易维护和模块化。 例如,
<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-2.5.xsd">
 
	<import resource="config/customer.xml"/>
        <import resource="config/scheduler.xml"/>
 
</beans>

Spring AOP通知实例

Spring AOP(面向方面编程)框架,用于在模块化方面的横切关注点。简单得说,它只是一个拦截器拦截一些过程,例如,当一个方法执行,Spring AOP 可以劫持一个执行的方法,在方法执行之前或之后添加额外的功能。
在Spring AOP中,有 4 种类型通知(advices)的支持:
  • 通知(Advice)之前 - 该方法执行前运行
  • 通知(Advice)返回之后 – 运行后,该方法返回一个结果
  • 通知(Advice)抛出之后 – 运行方法抛出异常后,
  • 环绕通知 – 环绕方法执行运行,结合以上这三个通知。

Spring AOP 通知

现在,附加 Spring AOP 建议到上述的客户服务。

1. 之前通知

它会在方法执行之前执行。创建一个实现 MethodBeforeAdvice 接口的类。
package com.yiibai.aop;

import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;

public class HijackBeforeMethod implements MethodBeforeAdvice
{
	@Override
	public void before(Method method, Object[] args, Object target)
		throws Throwable {
	        System.out.println("HijackBeforeMethod : Before method hijacked!");
	}
}
在 bean 配置文件(applicationContext.xml),创建一个 bean 的 HijackBeforeMethod 类,并命名为“customerServiceProxy” 作为一个新的代理对象。
  • ‘target’ – 定义你想拦截的bean。
  • ‘interceptorNames’ – 定义要应用这个代理/目标对象的类(通知)。
<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-2.5.xsd">

	<bean id="customerService" class="com.yiibai.customer.services.CustomerService">
		<property name="name" value="Yiibai Mook Kim" />
		<property name="url" value="http://www.yiibai.com" />
	</bean>

	<bean id="hijackBeforeMethodBean" class="com.yiibai.aop.HijackBeforeMethod" />

	<bean id="customerServiceProxy" 
                 class="org.springframework.aop.framework.ProxyFactoryBean">

		<property name="target" ref="customerService" />

		<property name="interceptorNames">
			<list>
				<value>hijackBeforeMethodBean</value>
			</list>
		</property>
	</bean>
</beans>
再次运行它,现在得到新的 customerServiceProxy bean,而不是原来的CustomerService bean。
package com.yiibai.common;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.yiibai.customer.services.CustomerService;

public class App {
	public static void main(String[] args) {
		ApplicationContext appContext = new ClassPathXmlApplicationContext(
				new String[] { "Spring-Customer.xml" });

		CustomerService cust = 
                                (CustomerService) appContext.getBean("customerServiceProxy");

		System.out.println("*************************");
		cust.printName();
		System.out.println("*************************");
		cust.printURL();
		System.out.println("*************************");
		try {
			cust.printThrowException();
		} catch (Exception e) {

		}

	}
}

输出结果

*************************
HijackBeforeMethod : Before method hijacked!
Customer name : Yiibai Mook Kim
*************************
HijackBeforeMethod : Before method hijacked!
Customer website : http://www.yiibai.com
*************************
HijackBeforeMethod : Before method hijacked!
它将运行 HijackBeforeMethod 的 before() 方法,在每个 CustomerService 的方法之前执行。

2.返回后通知
该方法返回一个结果之后它将执行。创建一个实现AfterReturningAdvice接口的类。
package com.yiibai.aop;

import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;

public class HijackAfterMethod implements AfterReturningAdvice
{
	@Override
	public void afterReturning(Object returnValue, Method method,
		Object[] args, Object target) throws Throwable {
	        System.out.println("HijackAfterMethod : After method hijacked!");
	}
}
bean配置文件
<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-2.5.xsd">

	<bean id="customerService" class="com.yiibai.customer.services.CustomerService">
		<property name="name" value="Yong Mook Kim" />
		<property name="url" value="http://www.yiibai.com" />
	</bean>

	<bean id="hijackAfterMethodBean" class="com.yiibai.aop.HijackAfterMethod" />

	<bean id="customerServiceProxy" 
                class="org.springframework.aop.framework.ProxyFactoryBean">

		<property name="target" ref="customerService" />

		<property name="interceptorNames">
			<list>
				<value>hijackAfterMethodBean</value>
			</list>
		</property>
	</bean>
</beans>
再次运行,输出
*************************
Customer name : Yiibai Mook Kim
HijackAfterMethod : After method hijacked!
*************************
Customer website : http://www.yiibai.com
HijackAfterMethod : After method hijacked!
*************************
它将运行 HijackAfterMethod 的 afterReturning()方法,在每次 CustomerService 方法返回结果之后。

3.抛出后通知
它将在执行方法抛出一个异常后。创建一个实现ThrowsAdvice接口的类,并创建一个afterThrowing方法拦截抛出:IllegalArgumentException异常。
package com.yiibai.aop;

import org.springframework.aop.ThrowsAdvice;

public class HijackThrowException implements ThrowsAdvice {
	public void afterThrowing(IllegalArgumentException e) throws Throwable {
		System.out.println("HijackThrowException : Throw exception hijacked!");
	}
}
bean配置文件
<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-2.5.xsd">

	<bean id="customerService" class="com.yiibai.customer.services.CustomerService">
		<property name="name" value="Yong Mook Kim" />
		<property name="url" value="http://www.yiibai.com" />
	</bean>

	<bean id="hijackThrowExceptionBean" class="com.yiibai.aop.HijackThrowException" />

	<bean id="customerServiceProxy" 
                 class="org.springframework.aop.framework.ProxyFactoryBean">

		<property name="target" ref="customerService" />

		<property name="interceptorNames">
			<list>
				<value>hijackThrowExceptionBean</value>
			</list>
		</property>
	</bean>
</beans>
再次运行,输出
*************************
Customer name : Yiibai Mook Kim
*************************
Customer website : http://www.yiibai.com
*************************
HijackThrowException : Throw exception hijacked!
它将运行 HijackThrowException 的 afterThrowing()方法,如果 CustomerService 的方法抛出异常。

4.环绕通知

它结合了上面的三个通知,在方法执行过程中执行。创建一个实现了MethodInterceptor接口的类。必须调用“methodInvocation.proceed();” 继续在原来的方法执行,否则原来的方法将不会执行。

package com.yiibai.aop;

import java.util.Arrays;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class HijackAroundMethod implements MethodInterceptor {
	@Override
	public Object invoke(MethodInvocation methodInvocation) throws Throwable {

		System.out.println("Method name : "
				+ methodInvocation.getMethod().getName());
		System.out.println("Method arguments : "
				+ Arrays.toString(methodInvocation.getArguments()));

		// same with MethodBeforeAdvice
		System.out.println("HijackAroundMethod : Before method hijacked!");

		try {
			// proceed to original method call
			Object result = methodInvocation.proceed();

			// same with AfterReturningAdvice
			System.out.println("HijackAroundMethod : Before after hijacked!");

			return result;

		} catch (IllegalArgumentException e) {
			// same with ThrowsAdvice
			System.out.println("HijackAroundMethod : Throw exception hijacked!");
			throw e;
		}
	}
}
bean配置文件
<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-2.5.xsd">

	<bean id="customerService" class="com.yiibai.customer.services.CustomerService">
		<property name="name" value="Yong Mook Kim" />
		<property name="url" value="http://www.yiibai.com" />
	</bean>

	<bean id="hijackAroundMethodBean" class="com.yiibai.aop.HijackAroundMethod" />

	<bean id="customerServiceProxy" 
                class="org.springframework.aop.framework.ProxyFactoryBean">

		<property name="target" ref="customerService" />

		<property name="interceptorNames">
			<list>
				<value>hijackAroundMethodBean</value>
			</list>
		</property>
	</bean>
</beans>
再次运行,输出
*************************
Method name : printName
Method arguments : []
HijackAroundMethod : Before method hijacked!
Customer name : YiiBai Mook Kim
HijackAroundMethod : Before after hijacked!
*************************
Method name : printURL
Method arguments : []
HijackAroundMethod : Before method hijacked!
Customer website : http://www.yiibai.com 
HijackAroundMethod : Before after hijacked!
*************************
Method name : printThrowException
Method arguments : []
HijackAroundMethod : Before method hijacked!
HijackAroundMethod : Throw exception hijacked!

它将运行HijackAroundMethod 的 invoke()方法,在每一个 CustomerService 方法执行后。

总结

大部分的 Spring 开发者都只是实现了“环绕通知”,因为它可以对所有通知类型,但更好的做法应该是选择最合适的通知类型来满足要求。
切入点
在这个例子中,在一客户服务类中的所有方法都自动拦截(通知)。但在大多数情况下,可能需要使用 切入点和Advisor通过它的方法名拦截它的方法。

1.切入点 - 名称匹配的例子

File : HijackAroundMethod.java

package com.yiibai.aop;

import java.util.Arrays;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class HijackAroundMethod implements MethodInterceptor {
	@Override
	public Object invoke(MethodInvocation methodInvocation) throws Throwable {

		System.out.println("Method name : "
				+ methodInvocation.getMethod().getName());
		System.out.println("Method arguments : "
				+ Arrays.toString(methodInvocation.getArguments()));

		System.out.println("HijackAroundMethod : Before method hijacked!");

		try {
			Object result = methodInvocation.proceed();
			System.out.println("HijackAroundMethod : Before after hijacked!");

			return result;

		} catch (IllegalArgumentException e) {

			System.out.println("HijackAroundMethod : Throw exception hijacked!");
			throw e;
		}
	}
}
全部bean配置文件
<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-2.5.xsd">

	<bean id="customerService" class="com.yiibai.customer.services.CustomerService">
		<property name="name" value="Yiibai" />
		<property name="url" value="http://www.yiibai.com" />
	</bean>

	<bean id="hijackAroundMethodBeanAdvice" class="com.yiibai.aop.HijackAroundMethod" />

	<bean id="customerServiceProxy" 
                class="org.springframework.aop.framework.ProxyFactoryBean">

		<property name="target" ref="customerService" />

		<property name="interceptorNames">
			<list>
				<value>customerAdvisor</value>
			</list>
		</property>
	</bean>

	<bean id="customerYiibaicut" 
                class="org.springframework.aop.support.NameMatchMethodYiibaicut">
		<property name="mappedName" value="printName" />
	</bean>

	<bean id="customerAdvisor" 
                 class="org.springframework.aop.support.DefaultYiibaicutAdvisor">
		<property name="pointcut" ref="customerYiibaicut" />
		<property name="advice" ref="hijackAroundMethodBeanAdvice" />
	</bean>

</beans>

2.切入点 - 正则表达式的例子

也可以通过使用正则表达式匹配切入点方法的名称  – RegexpMethodYiibaicutAdvisor.

<bean id="customerAdvisor"
		class="org.springframework.aop.support.RegexpMethodYiibaicutAdvisor">
		<property name="patterns">
			<list>
				<value>.*URL.*</value>
			</list>
		</property>

		<property name="advice" ref="hijackAroundMethodBeanAdvice" />
	</bean> 

现在,它拦截方法名称中有“URL”的方法。在实践中,可以用它来管理DAO层,声明“.*DAO.*” 拦截所有的DAO类来支持事务。

Spring AOP拦截器的序列


3个拦截器在事务管理器拦截器(matchGenericTxInterceptor)之前执行。
为了解决这个问题,必须改变拦截器 XML文件的顺序,如下面的(把 matchGenericTxInterceptor 放在顶部)。
<bean id="testAutoProxyCreator"
        class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
	<property name="interceptorNames">
		<list>
            <idref bean="matchGenericTxInterceptor" />
			<idref bean="urlInterceptorInsert" />
			<idref bean="urlInterceptorCommit" />
			<idref bean="urlInterceptorRelease" />
		</list>
	</property>
	<property name="beanNames">
		<list>
			<idref local="urlBo" />
		</list>
	</property>
</bean>

注 Spring AOP的拦截器的顺序对功能有影响。

Spring AOP+AspectJ注解实例

在本教程中,我们将向你展示如何将AspectJ注解集成到Spring AOP框架。在这个Spring AOP+ AspectJ 示例中,让您轻松实现拦截方法。
常见AspectJ的注解:
  1. @Before – 方法执行前运行
  2. @After – 运行在方法返回结果后
  3. @AfterReturning – 运行在方法返回一个结果后,在拦截器返回结果。
  4. @AfterThrowing – 运行方法在抛出异常后,
  5. @Around – 围绕方法执行运行,结合以上这三个通知。
注意

启用AspectJ

在 Spring 配置文件,把“<aop:aspectj-autoproxy />”,并定义Aspect(拦截)和普通的bean。

File : applicationContext.xml

<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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
	http://www.springframework.org/schema/aop 
	http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

	<aop:aspectj-autoproxy />

	<bean id="customerBo" class="com.yiibai.customer.bo.impl.CustomerBoImpl" />

	<!-- Aspect -->
	<bean id="logAspect" class="com.yiibai.aspect.LoggingAspect" />

</beans>

 AspectJ @Before

在下面例子中,logBefore()方法将在 customerBo接口的 addCustomer()方法的执行之前被执行。
AspectJ的“切入点”是用来声明哪种方法将被拦截,应该参考 Spring AOP切入点指南,支持切入点表达式的完整列表。

File : LoggingAspect.java

package com.yiibai.aspect;

import org.aspectj.lang.JoinYiibai;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class LoggingAspect {

	@Before("execution(* com.yiibai.customer.bo.CustomerBo.addCustomer(..))")
	public void logBefore(JoinYiibai joinYiibai) {

		System.out.println("logBefore() is running!");
		System.out.println("hijacked : " + joinYiibai.getSignature().getName());
		System.out.println("******");
	}

}

AspectJ @After

在下面例子中,logAfter()方法将在 customerBo 接口的 addCustomer()方法的执行之后执行。

File : LoggingAspect.java

package com.yiibai.aspect;

import org.aspectj.lang.JoinYiibai;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.After;

@Aspect
public class LoggingAspect {

	@After("execution(* com.yiibai.customer.bo.CustomerBo.addCustomer(..))")
	public void logAfter(JoinYiibai joinYiibai) {

		System.out.println("logAfter() is running!");
		System.out.println("hijacked : " + joinYiibai.getSignature().getName());
		System.out.println("******");

	}

}

ectJ @AfterReturning

在下面例子中,logAfterReturning()方法将在 customerBo 接口的addCustomerReturnValue()方法执行之后执行。此外,还可以截取返回的值使用“returning”属性。

要截取返回的值,对“returning”属性(结果)的值必须用相同的方法参数(结果)。

File : LoggingAspect.java

package com.yiibai.aspect;

import org.aspectj.lang.JoinYiibai;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;

@Aspect
public class LoggingAspect {

   @AfterReturning(
      pointcut = "execution(* com.yiibai.customer.bo.CustomerBo.addCustomerReturnValue(..))",
      returning= "result")
   public void logAfterReturning(JoinYiibai joinYiibai, Object result) {

	System.out.println("logAfterReturning() is running!");
	System.out.println("hijacked : " + joinYiibai.getSignature().getName());
	System.out.println("Method returned value is : " + result);
	System.out.println("******");
   }
}

AspectJ @AfterReturning

在下面的例子中,如果 customerBo 接口的addCustomerThrowException()方法抛出异常logAfterThrowing()方法将被执行。

File : LoggingAspect.java

package com.yiibai.aspect;

import org.aspectj.lang.JoinYiibai;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;

@Aspect
public class LoggingAspect {

   @AfterThrowing(
      pointcut = "execution(* com.yiibai.customer.bo.CustomerBo.addCustomerThrowException(..))",
      throwing= "error")
    public void logAfterThrowing(JoinYiibai joinYiibai, Throwable error) {

	System.out.println("logAfterThrowing() is running!");
	System.out.println("hijacked : " + joinYiibai.getSignature().getName());
	System.out.println("Exception : " + error);
	System.out.println("******");

    }
}

AspectJ @Around

在下面例子中,logAround()方法将在customerBo接口的addCustomerAround()方法执行之前执行, 必须定义“joinYiibai.proceed();” 控制何时拦截器返回控制到原来的addCustomerAround()方法。

File : LoggingAspect.java

package com.yiibai.aspect;

import org.aspectj.lang.ProceedingJoinYiibai;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;

@Aspect
public class LoggingAspect {

   @Around("execution(* com.yiibai.customer.bo.CustomerBo.addCustomerAround(..))")
   public void logAround(ProceedingJoinYiibai joinYiibai) throws Throwable {

	System.out.println("logAround() is running!");
	System.out.println("hijacked method : " + joinYiibai.getSignature().getName());
	System.out.println("hijacked arguments : " + Arrays.toString(joinYiibai.getArgs()));
		
	System.out.println("Around before is running!");
	joinYiibai.proceed(); //continue on the intercepted method
	System.out.println("Around after is running!");
		
	System.out.println("******");

   }
	
}
在本教程中,我们将向你展示如何转换上章节中  Spring AOP+AspectJ 注解转成基于XML的配置。
对于那些不喜欢注释,使用JDK1.4,则可以基于XML,而不使用 AspectJ。
再次回顾上个 customerBo 接口中的几个方法,以后你将学会如何在 XML文件实现 AspectJ 拦截。
package com.yiibai.customer.bo;

public interface CustomerBo {

	void addCustomer();
	
	String addCustomerReturnValue();
	
	void addCustomerThrowException() throws Exception;
	
	void addCustomerAround(String name);
}

1. AspectJ <aop:before> = @Before

AspectJ @Before 示例.

package com.yiibai.aspect;

import org.aspectj.lang.JoinYiibai;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class LoggingAspect {

	@Before("execution(* com.yiibai.customer.bo.CustomerBo.addCustomer(..))")
	public void logBefore(JoinYiibai joinYiibai) {
		//...
	}

} 

在XML同等功能,使用 <aop:before>.

<!-- Aspect -->
<bean id="logAspect" class="com.yiibai.aspect.LoggingAspect" />

<aop:config>

  <aop:aspect id="aspectLoggging" ref="logAspect" >

     <!-- @Before -->
     <aop:pointcut id="pointCutBefore"
	expression="execution(* com.yiibai.customer.bo.CustomerBo.addCustomer(..))" />

     <aop:before method="logBefore" pointcut-ref="pointCutBefore" />
			
  </aop:aspect>

</aop:config>

2. AspectJ <aop:after> = @After

AspectJ @After 示例.

package com.yiibai.aspect;

import org.aspectj.lang.JoinYiibai;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.After;

@Aspect
public class LoggingAspect {

	@After("execution(* com.yiibai.customer.bo.CustomerBo.addCustomer(..))")
	public void logAfter(JoinYiibai joinYiibai) {
		//...
	}

} 

在XML同等功能,使用 <aop:after>实现。

<!-- Aspect -->
<bean id="logAspect" class="com.yiibai.aspect.LoggingAspect" />

<aop:config>

  <aop:aspect id="aspectLoggging" ref="logAspect" >

     <!-- @After -->
     <aop:pointcut id="pointCutAfter"
	expression="execution(* com.yiibai.customer.bo.CustomerBo.addCustomer(..))" />

     <aop:after method="logAfter" pointcut-ref="pointCutAfter" />
			
  </aop:aspect>

</aop:config>

3. AspectJ <aop:after-returning> = @AfterReturning

AspectJ @AfterReturning 示例.

package com.yiibai.aspect;

import org.aspectj.lang.JoinYiibai;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;

@Aspect
public class LoggingAspect {

  @AfterReturning(
   pointcut = "execution(* com.yiibai.customer.bo.CustomerBo.addCustomerReturnValue(..))",
   returning= "result")
   public void logAfterReturning(JoinYiibai joinYiibai, Object result) {
	//...
   }

}

在XML同等功能 - 使用 <aop:after-returning>.

<!-- Aspect -->
<bean id="logAspect" class="com.yiibai.aspect.LoggingAspect" />

<aop:config>

  <aop:aspect id="aspectLoggging" ref="logAspect" >

    <!-- @AfterReturning -->
    <aop:pointcut id="pointCutAfterReturning"
      expression="execution(* com.yiibai.customer.bo.CustomerBo.addCustomerReturnValue(..))" />

    <aop:after-returning method="logAfterReturning" returning="result" 
      pointcut-ref="pointCutAfterReturning" />
			
  </aop:aspect>

</aop:config>

4. AspectJ <aop:after-throwing> = @AfterReturning

AspectJ @AfterReturning 示例.

package com.yiibai.aspect;

import org.aspectj.lang.JoinYiibai;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;

@Aspect
public class LoggingAspect {

  @AfterThrowing(
   pointcut = "execution(* com.yiibai.customer.bo.CustomerBo.addCustomerThrowException(..))",
   throwing= "error")
  public void logAfterThrowing(JoinYiibai joinYiibai, Throwable error) {
	//...
  }
}

在XML同等功能 - 使用 <aop:after-throwing>.

<!-- Aspect -->
<bean id="logAspect" class="com.yiibai.aspect.LoggingAspect" />

<aop:config>

  <aop:aspect id="aspectLoggging" ref="logAspect" >

    <!-- @AfterThrowing -->
    <aop:pointcut id="pointCutAfterThrowing"
      expression="execution(* com.yiibai.customer.bo.CustomerBo.addCustomerThrowException(..))" />
			
    <aop:after-throwing method="logAfterThrowing" throwing="error" 
      pointcut-ref="pointCutAfterThrowing"  />
			
  </aop:aspect>

</aop:config>

5. AspectJ <aop:after-around> = @Around

AspectJ @Around 示例.

package com.yiibai.aspect;

import org.aspectj.lang.ProceedingJoinYiibai;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;

@Aspect
public class LoggingAspect {

	@Around("execution(* com.yiibai.customer.bo.CustomerBo.addCustomerAround(..))")
	public void logAround(ProceedingJoinYiibai joinYiibai) throws Throwable {
		//...
	}
	
}

在XML同等功能 - 使用 <aop:after-around>.

<!-- Aspect -->
<bean id="logAspect" class="com.yiibai.aspect.LoggingAspect" />

<aop:config>

   <aop:aspect id="aspectLoggging" ref="logAspect" >

    <!-- @Around -->
   <aop:pointcut id="pointCutAround"
      expression="execution(* com.yiibai.customer.bo.CustomerBo.addCustomerAround(..))" />
			
   <aop:around method="logAround" pointcut-ref="pointCutAround"  />
			
  </aop:aspect>

</aop:config>

完整的 XML 实例

查看完整的基于XML的 AspectJ 配置文件。
<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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
	http://www.springframework.org/schema/aop 
	http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

<aop:aspectj-autoproxy />

<bean id="customerBo" class="com.yiibai.customer.bo.impl.CustomerBoImpl" />

<!-- Aspect -->
<bean id="logAspect" class="com.yiibai.aspect.LoggingAspect" />

<aop:config>

  <aop:aspect id="aspectLoggging" ref="logAspect">

    <!-- @Before -->
    <aop:pointcut id="pointCutBefore"
      expression="execution(* com.yiibai.customer.bo.CustomerBo.addCustomer(..))" />

    <aop:before method="logBefore" pointcut-ref="pointCutBefore" />

    <!-- @After -->
    <aop:pointcut id="pointCutAfter"
       expression="execution(* com.yiibai.customer.bo.CustomerBo.addCustomer(..))" />

    <aop:after method="logAfter" pointcut-ref="pointCutAfter" />

    <!-- @AfterReturning -->
    <aop:pointcut id="pointCutAfterReturning"
       expression="execution(* com.yiibai.customer.bo.CustomerBo.addCustomerReturnValue(..))" />

    <aop:after-returning method="logAfterReturning"
      returning="result" pointcut-ref="pointCutAfterReturning" />

    <!-- @AfterThrowing -->
    <aop:pointcut id="pointCutAfterThrowing"
      expression="execution(* com.yiibai.customer.bo.CustomerBo.addCustomerThrowException(..))" />

    <aop:after-throwing method="logAfterThrowing"
      throwing="error" pointcut-ref="pointCutAfterThrowing" />

    <!-- @Around -->
    <aop:pointcut id="pointCutAround"
      expression="execution(* com.yiibai.customer.bo.CustomerBo.addCustomerAround(..))" />

    <aop:around method="logAround" pointcut-ref="pointCutAround" />

  </aop:aspect>

</aop:config>

</beans>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值