AOP—Aspect-oriented Programming
面向方面编程。
基于代理类的ProxyFactoryBean的AOP实现
ProxyFactoryBean是FactoryBean接口的实现类。FactoryBean负责实例化一个Bean,
即
<bean id="logAdvice" class="com.xue.aop.LogAdvice"></bean>
而ProxyFactoryBean负责创建代理实例,他内部使用FactoryBean来完成这一工作。使用这个是创建AOP的最基本的方式。
例如:
数据访问层:
项目的Userao接口中声明两个方法
public interface UserDao { public void addUser(String username,String password); public void delUser(int id); }
UserDao的实现类:
public class UserDaoImpl implements UserDao { @Override public void addUser(String username, String password) { System.out.println(username+"用户添加成功"); } @Override public void delUser(int id) { System.out.println("编号为"+id+"的用户被删除"); } }
业务逻辑层:
在UserBiz中,声明两个方法:
public interface UserBiz { public void addUser(String username, String passworld); public void delUser(int id); }
UserBiz的实现类:
public class UserBizImpl implements UserBiz { UserDao userDao; //set方法用于依赖注入 public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public void addUser(String username, String passworld) { userDao.addUser(username,passworld); } @Override public void delUser(int id) { userDao.delUser(id); } }
方面代码:
实现特定功能的方面代码在AOP概念中被称为“通知(Advice)”。通知分为前置通知、后置通知、环绕通知和异常通知。
前置通知:(log4j的配置不做介绍)
public class LogAdvice implements MethodBeforeAdvice { private Logger logger=Logger.getLogger(LogAdvice.class); @Override public void before(Method method, Object[] args, Object target) throws Throwable { //获取被调用的类名 String targetClassname=target.getClass().getName(); //获取被调用的方法名 String targetMethodname=method.getName(); String logInfoText="前置通知:"+targetClassname+"类的"+targetMethodname+"方法开始执行"; logger.info(logInfoText); } }
配置ApplicationContext.xml文件:
<bean id="userDao" class="com.xue.dao.UserDaoImpl"></bean> <bean id="userBiz" class="com.xue.dao.UserBizImpl"> <property name="userDao" ref="userDao"></property> </bean> <bean id="logAdvice" class="com.xue.aop.LogAdvice"></bean> <!--使用spring代理工厂定义一个代理,通过他访问业务类中的方法--> <bean id="ub" class="org.springframework.aop.framework.ProxyFactoryBean"> <!--指定代理接口--> <property name="proxyInterfaces"> <value>com.xue.dao.UserBiz</value> </property> <!--指定通知--> <property name="interceptorNames"> <list> <value>logAdvice</value> </list> </property> <!--指定目标对象--> <property name="target" ref="userBiz"></property> </bean>
测试类:
public class Test { public static void main(String[] args) { ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml"); UserBiz userBiz= (UserBiz) context.getBean("ub"); userBiz.addUser("zhangsan","123"); userBiz.delUser(1); } }
总结:虽然没有看过源码,但个人感觉,测试类中UserBiz通过getBean(“ub”)获取实例,是ProxyFactoryBean会自动在配置的xml中返回实例,并且让指定的通知在方法执行前执行。
LogAdvice(指定的通知)做的事:获取类名、方法名,将其写入日志中。
结果:
[INFO ] [18:02:32] com.xue.aop.LogAdvice - 前置通知:com.xue.dao.UserBizImpl类的addUser方法开始执行
zhangsan用户添加成功
[INFO ] [18:02:32] com.xue.aop.LogAdvice - 前置通知:com.xue.dao.UserBizImpl类的delUser方法开始执行
编号为1的用户被删除