1、AOP的使用场景
在业务模块中,存在一种通用的系统性需求,如日志、事务管理等。
在常规的方法中,会在业务代码中直接嵌入平台代码。但这样是2种不相关的代码混杂,不方便管理。
通过AOP就可以实现在不侵入业务代码的情况下,实现统一的平台需求。
举个例子,如一个类有100个方法,都要嵌入日志代码吗?修改了怎么办?
AOP是一种编程概念,通过JDK远程方法也可以实现,spring中更容易了,写写配置就好。
2、AOP的术语
- 切面:Aspect,交叉的业务逻辑,如日志、事务管理。也叫对业务代码增强。
- 织入:Weaving,把切面代码插入主业务代码过程。
- 连接点:JoinPort,可以被织入的方法。指主业务中的方法。
- 切入点:PointCut,切面实际织入的方法。不是所有连接点都被织入。
- 目标对象:Target,目标对象,要被增强的对象。
- 通知:可以指定织入时机,无法指定切入点。每个连接点都会增强。
- 顾问:包含通知,可以针对具体连接点。
简单来说:AOP就是在业务代码中插入增强代码。包含2类4个要素
- 业务代码侧:目标代码,目标方法。
- 增强代码侧:增强的内容,触发的时机。
3、用JDK实现AOP:动态代理
public interface IUser {
public String sayHello(String msg);
public String goRun();
}
public class UserImpl implements IUser {
@Override
public String sayHello(String msg) {
System.out.println( "你好,"+msg);
return "";
}
public String goRun() {
System.out.println( "i'm running");
return "i'm running";
}
public static void main(String[] args) {
final IUser target3 = new UserImpl();
/*a proxy class that is defined in the specified class loader
* and that implements the specified interfaces
* 所以第1、2个参数分别是目标类和目标类实现的接口*/
IUser proxy3 = (IUser) Proxy.newProxyInstance(target3.getClass().getClassLoader(), target3.getClass().getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/**代理类里重构了invoke方法,代理类的方法调用时,是派发到代理类内部的
目标类上执行的。
但是,invoke方法里可以添加切面了*/
//前置通知
System.out.println("判断用户是否有权限进行操作");
//目标类方法
Object obj = method.invoke(target3, args);
//后置通知
System.out.println("记录用户执行操作的用户信息、更改内容和时间等");
return obj;
}
});
Object obj3 = proxy3.sayHello("地球");
}
}
实现方法:
1.目标类必须实现了接口;
2.用Proxy.newProxyInstance创建代理类
3.代理类包含了目标类实例,重构了invoke方法
4.在代理类的invoke方法中,执行目标类的方法,并可以加入前后通知
4、spring中AOP的实现
增强代码,已后置通知为例
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("执行前置通知方法");
}
}
ApplicationContext.xml配置
<!--注册目标对象-->
<bean id="myUserSerice" class="master3.UserImpl"></bean>
<!--注册切面:通知-->
<bean id="myAdvice" class="master3.MyMethodBeforeAdvice"/>
<!--注册代理工厂-->
<bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--指定目标对象,没有目标方法,因为是advice,不能指定方法,全部增强了-->
<property name="target" ref="myUserSerice"> </property>
<!--指定增强代码,时机是后置通知,通过继承设定了-->
<property name="interceptorNames" value="myAdvice" ></property>
</bean>
测试代码:
@Test
public void test01(){
ApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContext.xml");
IUser myUser=(IUser)ac.getBean("serviceProxy");
myUser.sayHello("地球");
myUser.goRun();
}
输出
执行前置通知方法
你好,地球
执行前置通知方法
i'm running
总结
- AOP是一种编程方法
- 适用于不修改业务代码的情况下对其增强
- 记住2类4概念:目标代码,目标方法;增强代码,触发时机。
- spring里改改参数文件就能实现