自己写的BeforeAdvice类实现MethodBeforeAdvice类,重写里面的方法before()
切面类MyLogger.java
//切面类
public class MyLogger {
public void log(String msg){
System.out.println("log:"+msg);
}
}
实体类Account.java
//银行账户
public class Account {
private int id;
private String name;
private double balance;//余额
get/set方法
...
}
dao层接口AccountDao.java
public interface AccountDao {
//取款 账号减去多少钱
void withdraw(Account acc,double amt);
//存款 账号加上多少钱
void deposit(Account acc,double amt);
}
dao层实现类AccountDaoImpl.java
public class AccountDaoImpl implements AccountDao{
//取款
@Override
public void withdraw(Account acc, double amt) {
System.out.println("账号成功取款"+amt);
}
//存款
@Override
public void deposit(Account acc, double amt) {
System.out.println("账号成功存款"+amt);
}
}
service层接口IAccountService.java
public interface IAccountService {
//转账
void bankAction();
}
目标对象,service层实现类AccountServiceImpl.java
//目标对象(target)
public class AccountServiceImpl implements IAccountService{
private AccountDao accountDao;
private Account account;
get/set方法
...
@Override
public void bankAction() {
accountDao.withdraw(account, 100);
accountDao.deposit(account, 100);
}
}
自己写个前置通知类BeforeAdvice实现MethodBeforeAdvice
//前置通知
//负责把切面类中的代码织入到目标对象中指定的方法执行之前
public class BeforeAdvice implements MethodBeforeAdvice {
// 引入切面类
private MyLogger logger;
// 将来通过set注入的方式赋值logger对象
public MyLogger getLogger() {
return logger;
}
public void setLogger(MyLogger logger) {
this.logger = logger;
}
// method参数:将来要调用的方法(也就是连接点)
// args参数:将来调用方法时传递的参数
// target参数:将来指定的目标对象
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
// 这里面就表示前置通知要干的事情
logger.log("前置通知-" + method.getName() + "方法开始执行了...");
// 这里不需要使用反射调用目标对象中的方法,因为spring会自动帮我们调用
// 如果你还用反射调用目标方法,则代表该方法被调用两次
}
}
配置xml文件: 注意ProxyFactoryBean的配置,htmlsingle中搜索即可
before.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" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<!-- 配置切面类 -->
<bean name="logger" class="com.briup.aop.aspect.MyLogger"></bean>
<!-- 配置前置通知 -->
<bean name="beforeAdvice" class="com.briup.aop.before.BeforeAdvice">
<!-- 注入切面类对象 -->
<property name="logger" ref="logger"></property>
</bean>
<!-- 配置dao层对象accountDao和account对象,为了给service注入 -->
<bean name="accountDao" class="com.briup.aop.dao.AccountDaoImpl"></bean>
<bean name="account" class="com.briup.aop.pojo.Account">
<property name="id" value="1"></property>
<property name="name" value="tom"></property>
<property name="balance" value="20000"></property>
</bean>
<!-- 配置目标对象 -->
<bean name="target" class="com.briup.aop.service.AccountServiceImpl">
<!-- 注入相关的类 -->
<property name="accountDao" ref="accountDao"></property>
<property name="account" ref="account"></property>
</bean>
<!-- 配置代理对象 -->
<!-- 这里使用的是spring的一个代理对象工厂类产生的 -->
<!-- 配置产生代理对象的工厂类 -->
<!--id是生产的对象名字,测试类中getBean获得 -->
<!--class="org.springframework.aop.framework.ProxyFactoryBean"固定的-->
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 注入需要实现的接口,proxyInterfaces固定的,value自己添加 -->
<property name="proxyInterfaces">
<!-- 目标类接口类列表 -->
<list>
<value>com.briup.aop.service.IAccountService</value>
</list>
</property>
<!-- 注入被代理的目标对象,代理的是哪个目标类 -->
<property name="target" ref="target" />
<!-- 注入通知(拦截器) name="interceptorNames"固定的-->
<property name="interceptorNames">
<list>
<!-- 拦截器的名字 -->
<value>beforeAdvice</value>
</list>
</property>
</bean>
</beans>
我们要做的事情:在转账方法(bankAction)执行之前进行一个日志输出
测试:
@Test
public void aop_before() {
try {
String path = "com/briup/aop/before/before.xml";
ApplicationContext container = new ClassPathXmlApplicationContext(path);
//获取代理对象
IAccountService proxy=(IAccountService) container.getBean("proxy");
proxy.bankAction();
System.out.println("------------");
System.out.println(proxy.getClass());
System.out.println("------------");
//假如采用的是jdk方式代理,目标类独有的方法,代理类是无法调用执行的
} catch (Exception e) {
e.printStackTrace();
}
}