示例
首先举个栗子,演示 Spring 的注入,项目工程视图如下
定义一个Tutorial类
package com.ggli.aop.model;
public class Tutorial {
private String name;
private String url;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public void printName() {
System.out.println("Tutorial name: " + this.name);
}
public void printUrl() {
System.out.println("Tutorial url: " + this.url);
}
public void printThrowException() {
throw new IllegalArgumentException();
}
}
在关联 Spring 的 applicationContext.xml 中配置 bean
<?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">
<bean id="tutorial1" class="com.ggli.aop.model.Tutorial">
<property name="name" value="Java Essential Training"/>
<property name="url" value="https://www.lynda.com/Java-tutorials/Java-Essential-Training/377484-2.html"/>
</bean>
<bean id="tutorial2" class="com.ggli.aop.model.Tutorial">
<property name="name" value="Overview of IDEs for Java"/>
<property name="url" value="https://www.lynda.com/Development-Tools-tutorials/Overview-IDEs-Java/486760-2.html"/>
</bean>
<bean id="tutorial3" class="com.ggli.aop.model.Tutorial">
<property name="name" value="Up and Running with Java Applications"/>
<property name="url" value="https://www.lynda.com/Java-tutorials/Up-Running-Java-Applications/435790-2.html"/>
</bean>
</beans>
使用 p 简化 bean 的属性赋值(convert to p-namespace)
首先,导入 p 的命名空间(不需要导入 xsi:schemaLocation)
xmlns:p="http://www.springframework.org/schema/p"
bean 定义就可以写为
<bean id="tutorial1" class="com.ggli.aop.model.Tutorial"
p:name="Java Essential Training" p:url="https://www.lynda.com/Java-tutorials/Java-Essential-Training/377484-2.html"/>
新建一个单元测试类
import com.ggli.aop.model.Tutorial;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UnitTest {
@Test
public void testObject() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Tutorial tutorial = (Tutorial) context.getBean("tutorial1");
System.out.println("------------------------------");
tutorial.printName();
tutorial.printUrl();
System.out.println("------------------------------");
try {
tutorial.printThrowException();
} catch (Exception e) {
}
}
}
静态工厂方法配置 bean
Java 程序源码
package com.ggli.aop.fatory;
import java.util.HashMap;
import java.util.Map;
public class StaticFactoryMethod {
public static Map<String, Tutorial> map = new HashMap<String, Tutorial>();
static {
map.put("Alice", new Tutorial(
"Java Essential Training",
"https://www.lynda.com/Java-tutorials/Java-Essential-Training/377484-2.html"));
map.put("Grace", new Tutorial(
"Overview of IDEs for Java",
"https://www.lynda.com/Development-Tools-tutorials/Overview-IDEs-Java/486760-2.html"));
}
public static Tutorial getTutorial(String key){
return map.get(key);
}
}
xml 配置
<!-- static factory method -->
<bean id="tutorial" factory-method="getTutorial" class="com.ggli.aop.fatory.StaticFactoryMethod">
<constructor-arg value="Alice" type="java.lang.String"></constructor-arg>
</bean>
实例工厂方法配置 bean
Java 程序源码
package com.ggli.aop.fatory;
import java.util.HashMap;
import java.util.Map;
public class InstanceFactoryMethod {
public static Map<String, Tutorial> map = new HashMap<String, Tutorial>();
static {
map.put("Alice", new Tutorial(
"Java Essential Training",
"https://www.lynda.com/Java-tutorials/Java-Essential-Training/377484-2.html"));
map.put("Grace", new Tutorial(
"Overview of IDEs for Java",
"https://www.lynda.com/Development-Tools-tutorials/Overview-IDEs-Java/486760-2.html"));
}
public static Tutorial getTutorial(String key){
return map.get(key);
}
}
xml 配置
<!-- instance factory method -->
<bean id="method" class="com.ggli.aop.fatory.InstanceFactoryMethod"/>
<bean id="tutorial" factory-bean="method" factory-method="getTutorial" class="com.ggli.aop.fatory.StaticFactoryMethod">
<constructor-arg value="Alice"></constructor-arg>
</bean>
AOP
Spring AOP 相当于一个拦截器,当一个方法执行时,Spring能够拦截正在执行的方法,在方法执行前或后增加额外的功能和处理。
Spring AOP 支持4种类型的通知
Type | Description |
---|---|
before advice | 在方法执行前执行 |
after returning advice | 在方法执行返回一个结果后执行 |
after throwing advice | 在方法执行中抛出异常时执行 |
around advice | 在方法执行前后和抛出异常时执行,综合了上述三种 |
下面分别介绍。
before advice
创建一个实现 MethodBeforeAdvice 接口的类,该类实现 before 方法,当被拦截的方法执行前,该 before 方法会被执行。
package com.ggli.aop.advice;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class BeforeAdvice implements MethodBeforeAdvice {
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("[Before method] " + o.getClass().getName() + "." + method.getName() + "()");
}
}
在 Spring 的 applicationContext.xml 中,创建BeforeAdvice类对应的 bean,以及一个代理的 bean
设置两个 property
- target:设置要拦截的 bean
- interceptorNames:设置作用于 proxy/target 上的通知
<?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">
<bean id="tutorial1" class="com.ggli.aop.model.Tutorial">
<property name="name" value="Java Essential Training"/>
<property name="url" value="https://www.lynda.com/Java-tutorials/Java-Essential-Training/377484-2.html"/>
</bean>
<bean id="beforeAdvice" class="com.ggli.aop.advice.BeforeAdvice"/>
<bean id="proxy1" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="tutorial1"/>
<property name="interceptorNames">
<list>
<value>beforeAdvice</value>
</list>
</property>
</bean>
</beans>
after advice
创建一个实现 AfterReturningAdvice 接口的类,在被拦截的方法运行返回结果后将执行类中的 afterReturning 方法
package com.ggli.aop.advice;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterAdvice implements AfterReturningAdvice {
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("[After method] " + o1.getClass().getName() + "." + method.getName() + "()");
}
}
修改 applicationContext.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">
<bean id="tutorial1" class="com.ggli.aop.model.Tutorial">
<property name="name" value="Java Essential Training"/>
<property name="url" value="https://www.lynda.com/Java-tutorials/Java-Essential-Training/377484-2.html"/>
</bean>
<bean id="beforeAdvice" class="com.ggli.aop.advice.BeforeAdvice"/>
<bean id="afterAdvice" class="com.ggli.aop.advice.AfterAdvice"/>
<bean id="proxy1" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="tutorial1"/>
<property name="interceptorNames">
<list>
<value>beforeAdvice</value>
<value>afterAdvice</value>
</list>
</property>
</bean>
</beans>
after throwing advice
创建一个类实现 ThrowsAdvice 接口。
package com.ggli.aop.advice;
import org.springframework.aop.ThrowsAdvice;
public class ExceptionAdvice implements ThrowsAdvice {
public void afterThrowing(IllegalArgumentException e) throws Throwable {
System.out.println("[ExceptionAdvice] sends the regards: " + e.toString());
}
}
修改 applicationContext.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">
<bean id="tutorial1" class="com.ggli.aop.model.Tutorial">
<property name="name" value="Java Essential Training"/>
<property name="url" value="https://www.lynda.com/Java-tutorials/Java-Essential-Training/377484-2.html"/>
</bean>
<bean id="beforeAdvice" class="com.ggli.aop.advice.BeforeAdvice"/>
<bean id="afterAdvice" class="com.ggli.aop.advice.AfterAdvice"/>
<bean id="exceptionAdvice" class="com.ggli.aop.advice.ExceptionAdvice"/>
<bean id="proxy1" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="tutorial1"/>
<property name="interceptorNames">
<list>
<value>beforeAdvice</value>
<value>afterAdvice</value>
<value>exceptionAdvice</value>
</list>
</property>
</bean>
</beans>
around advice
创建一个类实现 MethodInterceptor 接口,需要在方法中执行 Object result = methodInvocation.proceed() 方法才能得到执行,否则方法不会执行。
package com.ggli.aop.advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class AroundAdvice implements MethodInterceptor {
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
try {
System.out.println("[Around method] Before: " + methodInvocation.getMethod().getName());
Object obj = methodInvocation.proceed();
System.out.println("[Around method] After: " + methodInvocation.getMethod().getName());
return obj;
} catch (IllegalArgumentException e) {
System.out.println("[Around method] Exception: " + methodInvocation.getMethod().getName());
throw e;
}
}
}
修改 applicationContext.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">
<bean id="tutorial1" class="com.ggli.aop.model.Tutorial">
<property name="name" value="Java Essential Training"/>
<property name="url" value="https://www.lynda.com/Java-tutorials/Java-Essential-Training/377484-2.html"/>
</bean>
<bean id="tutorial2" class="com.ggli.aop.model.Tutorial">
<property name="name" value="Overview of IDEs for Java"/>
<property name="url" value="https://www.lynda.com/Development-Tools-tutorials/Overview-IDEs-Java/486760-2.html"/>
</bean>
<bean id="tutorial3" class="com.ggli.aop.model.Tutorial">
<property name="name" value="Up and Running with Java Applications"/>
<property name="url" value="https://www.lynda.com/Java-tutorials/Up-Running-Java-Applications/435790-2.html"/>
</bean>
<bean id="beforeAdvice" class="com.ggli.aop.advice.BeforeAdvice"/>
<bean id="afterAdvice" class="com.ggli.aop.advice.AfterAdvice"/>
<bean id="exceptionAdvice" class="com.ggli.aop.advice.ExceptionAdvice"/>
<bean id="aroundAdvice" class="com.ggli.aop.advice.AroundAdvice"/>
<bean id="proxy1" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="tutorial2"/>
<property name="interceptorNames">
<list>
<value>beforeAdvice</value>
<value>afterAdvice</value>
<value>exceptionAdvice</value>
</list>
</property>
</bean>
<bean id="proxy2" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="tutorial3"/>
<property name="interceptorNames">
<list>
<value>aroundAdvice</value>
</list>
</property>
</bean>
</beans>
单元测试类
import com.ggli.aop.model.Tutorial;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UnitTest {
@Test
public void testObject() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Tutorial tutorial = (Tutorial) context.getBean("tutorial1");
tutorial.printName();
System.out.println("------------------------------");
tutorial.printUrl();
System.out.println("------------------------------");
try {
tutorial.printThrowException();
} catch (Exception e) {
}
}
@Test
public void testAdvice() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Tutorial tutorial = (Tutorial) context.getBean("proxy1");
tutorial.printName();
System.out.println("------------------------------");
tutorial.printUrl();
try {
tutorial.printThrowException();
} catch (Exception e) {
}
}
@Test
public void testAround() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Tutorial tutorial = (Tutorial) context.getBean("proxy2");
tutorial.printName();
System.out.println("------------------------------");
tutorial.printUrl();
try {
tutorial.printThrowException();
} catch (Exception e) {
}
}
}