Table of Contents
AOP为Aspect Oriented Programming的缩写,意为:面向切面的编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容
首先我们使用java中的原生反射来演示一下动态代理:
1.JDK动态代理
假设现在在业务侧有如下一个类:UserServiceImpl.java
package org.example.service.impl;
import org.example.dao.UserDao;
import org.example.service.UserService;
public class UserServiceImpl implements UserService {
private UserDao userDao;
public UserServiceImpl() {
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void addUser() {
System.out.println("核心功能...");
}
@Override
public void play() {
System.out.println("哈哈哈我也是核心功能。。。");
}
}
某一天,我忽然想在该类的每个方法中加入一些新的业务逻辑,那该咋整呢?
java通过反射可以动态代理实解决此问题:
@Test
public void test2() {
final UserService userService = new UserServiceImpl();
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是额外的功能。。。。");
method.invoke(userService, args);
System.out.println("我也是额外功能。。。");
return null;
}
};
UserService proxy = (UserService) Proxy.newProxyInstance(AppTest.class.getClassLoader(), userService.getClass().getInterfaces(), invocationHandler);
proxy.addUser();
System.out.println("##################");
proxy.play();
}
运行结果:
2.使用Spring中的AOP模块中的动态代理
由上面的演示可见使用Java实现动态代理具有局限性和复杂性,于是Spring在其AOP中对此进行了简化
五种额外代理功能:
1.前置
package org.example.advice;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class BeforeAdvice implements MethodBeforeAdvice {
/**
* 主题逻辑,在核心代码之前执行
*
* @param method 当前执行的方法对象
* @param objects 方法的参数
* @param o 目标对象
* @throws Throwable
*/
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("i am method before" + method.getName() + "::args:" + objects.length + " target" + o);
}
}
2.后置
package org.example.advice;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterAdvice implements AfterReturningAdvice {
/**
* 在核心功能后执行
*
* @param o 核心功能返回值
* @param method 方法对象
* @param objects 方法的参数表
* @param o1 目标对象
* @throws Throwable
*/
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("i am method after:" + method.getName());
}
}
3.环绕
package org.example.advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class InterceptorAdvice implements MethodInterceptor {
/**
* @param methodInvocation
* @return 核心代码执行结果
* @throws Throwable
*/
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("我在你上面。。。");
Object proceed = methodInvocation.proceed();
System.out.println("我在你下面。。。");
return proceed;
}
}
4.异常
package org.example.advice;
import org.springframework.aop.ThrowsAdvice;
public class ErrorAdvice implements ThrowsAdvice {
public void afterThrowing(Exception e) {
e.printStackTrace();
System.out.println("呀呀呀!!!出错了");
}
}
applicationContext.xml的配置
<?xml version="1.0" encoding="UTF-8"?>
<!--
dtd:document type definition
xsd:xml schema definition
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userServiceImpl" class="org.example.service.impl.UserServiceImpl"/>
<bean id="beforeAdvice" class="org.example.advice.BeforeAdvice"/>
<!--编织-->
<aop:config>
<!-- 切入点-->
<aop:pointcut id="cutOne" expression="execution(* org.example.service.impl.UserServiceImpl.*(..))"/>
<aop:pointcut id="cutOne2" expression="execution(* org.example.service.impl.UserServiceImpl.play(..))"/>
<!--将某个额外功能编织到指定切入点中-->
<aop:advisor advice-ref="beforeAdvice" pointcut-ref="cutOne"/>
</aop:config>
</beans>
测试
/**
* AOP测试
*/
@Test
public void test3() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring/applicationContext.xml");
//使用目标bean id即可获取编制后的对象
UserService userServiceImpl = applicationContext.getBean("userServiceImpl", UserService.class);
userServiceImpl.play();
System.out.println("#####################");
userServiceImpl.addUser();
}
三种切入点表达式:
1.execution
<aop:pointcut id="cutOne" expression="execution(* org.example.service.impl.UserServiceImpl.*(..))"/>
2.within
描述包和类,类中的所有方法都切入
<aop:pointcut id="pc" experssion="com.dao.impl.UserDaoServiceImpl"/>
3.args
描述参数表,符合要求的方法都切入
<aop:pointcut id="pc" experssion="args(int , String , com.entity.User)"/>
谢谢观看!