设计模式(四) 手动实现AOP代理
1.事务的使用:
每次对数据库操作我们都需要开启事务,事务开启后,我们就需要对数据库进行一次或者多次操作,当操作完成后就需要提交事务。比如一个业务中多次操作数据库,但是当某个方法出错的时候,我们需要整体回滚,
所以我们把业务的操作绑定在一个事务中。)
2.手动实现aop管理事务
我们都知道,如果在业务流程代码中增加事务的开启与提交操作,那么我们在一个类中维护的将会是业务与事务的代码。代码少还可以,但是如果代码量很大,维护起来将显得臃肿复杂。那么我们能不能将业务与事务的代码剥离开来,分开进行维护呢?
答案肯定是可行的。下面我们通过手动实现AOP代理。
AOP 面向切面的编程:
AOP可以实现“业务代码”与“关注点代码”分离,关注点代码可以想象为事务的那部分代码。
代码示例:
IUserDao 接口对象
package com.murong.aop; //接口 public interface IUserDao { void save(); }
UserDao 目标对象
package com.murong.aop; import org.springframework.stereotype.Component; /** * 目标对象 */ @Component // 加入IOC容器 public class UserDao implements IUserDao { @Override public void save() { System.out.println("-----核心业务:保存!!!------"); } }
Aop 关注点代码类
package com.murong.aop; import org.springframework.stereotype.Component; /** * 关注点代码类 */ @Component // 加入IOC容器 public class Aop { // 重复执行的代码 public void begin() { System.out.println("事务开启"); } // 重复执行的代码 public void end() { System.out.println("事务结束"); } }
ProxyFactory 代理工厂
package com.murong.aop; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 代理工厂 * */ public class ProxyFactory { public static Object newProxyInstance(final Object target,final Aop aop) { // 生成代理对象的方法 return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { aop.begin();// 关注点代码 Object result = method.invoke(target, args);// 执行目标对象的方法 aop.end();// 关注点代码 return result; } }); } }
applicationContext spring配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd" default-autowire="byType"> <!-- 开启注解扫描 --> <context:component-scan base-package="com.murong.aop"></context:component-scan> <!-- 调用工厂方法,返回UserDao的代理对象 --> <bean id="userDao_proxy" class="com.murong.aop.ProxyFactory" factory-method="newProxyInstance"> <constructor-arg index="0" type="java.lang.Object" ref="userDao"></constructor-arg> <constructor-arg index="1" type="com.murong.aop.Aop" ref="aop"></constructor-arg> </bean> </beans>
App 测试类
package com.murong.aop; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { private ApplicationContext ac = new ClassPathXmlApplicationContext("com/murong/aop/applicationContext"); @Test public void test() { IUserDao dao = (IUserDao) ac.getBean("userDao_proxy"); dao.save(); } }
结果:
分析总结:
关注点代码,就是指重复执行的代码。
业务代码与关注点代码分离,好处?
-à 关注点代码写一次即可;
-à开发者只需要关注核心业务;
-à运行时期,执行核心业务代码时候动态植入关注点代码; 【代理】
人要耐得住寂寞,才能守得住繁华。人生最痛苦的就是拿不起放不下,不属于自己的快乐,及时放手也许是一种解脱,生活中没有谁对谁错,只有适不适合。当发现很多已经改变,更要面对的是事实。