自动代理生成器
前面的所有例子中所使用的代理对象,均是由ProxyFactoryBean代 理工具类生成的。
而该代理工具类存在着如下缺点:
1.一个代理对象只能代理一个Bean,即如果有两个Bean同时都要 织入同一个切面,这时,不仅要配置这两个Bean,即两个目标对象,同时 还要配置两个代理对象。
2.在客户类中获取Bean时,使用的是代理类的id,而非我们定义的 目标对象Bean的id。我们真正想要执行的应该是目标对象。从形式上看, 不符合正常的逻辑。 Spring提供了自动代理生成器,用于解决ProxyFactoryBean的问题。 常用的自动代理生成器有两个:
- 默认advisor自动代理生成器 (DefaultAdvisorAutoProxyCreator)
- Bean名称自动代理生成器(BeanNameAutoProxyCreator)
DefaultAdvisorAutoProxyCreator会为每一个目标对象织入所有匹配 的Advisor,不具有选择性。而BeanNameAutoProxyCreator的代理生成方式 是,根据bean的id,来为符合相应名称的类生成相应代理对象。
DefaultAdvisorAutoProxyCreator只能切入顾问,BeanNameAutoProxyCreator能切入顾问和通知
DefaultAdvisorAutoProxyCreator演示
1.创建两个通知(前置、后置)
public class MyAfterReturingAdvice implements AfterReturningAdvice {
/*
* @see org.springframework.aop.AfterReturningAdvice#afterReturning(java.lang.Object, java.lang.reflect.Method, java.lang.Object[], java.lang.Object)
* returnValue:目标方法返回值
* method:目标方法
* args:目标方法参数
* target:目标类的对象
*/
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("后置通知方法执行! 目标方法返回值:"+returnValue);
}
}
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("前置通知方法执行!");
}
}
2.主业务接口和目标类
//主业务接口
public interface IService {
//目标方法
void doSome();
//目标方法
void doOther();
}
//目标类
public class StudentServiceImpl implements IService {
@Override
public void doSome() {
System.out.println("Student主业务逻辑当中doSome()方法执行!");
}
@Override
public void doOther() {
System.out.println("Student主业务逻辑当中doOther()方法执行!");
}
public void doThird(){
System.out.println("1111111111111111111111");
}
}
//目标类
public class TeacherServiceImpl implements IService {
@Override
public void doSome() {
System.out.println("Teacher主业务逻辑当中doSome()方法执行!");
}
@Override
public void doOther() {
System.out.println("Teacher主业务逻辑当中doOther()方法执行!");
}
public void doThird(){
System.out.println("1111111111111111111111");
}
}
3.主配置文件
<?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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 注册目标类 -->
<bean id="studentServiceImpl" class="com.bjsxt.service.StudentServiceImpl"/>
<bean id="teacherServiceImpl" class="com.bjsxt.service.TeacherServiceImpl"/>
<!-- 注册前置通知 -->
<bean id="myMethodBeforeAdvice" class="com.bjsxt.advice.MyMethodBeforeAdvice"/>
<!-- 注册后置通知 -->
<bean id="myAfterReturningAdvice" class="com.bjsxt.advice.MyAfterReturingAdvice"/>
<!-- 注册顾问 -->
<bean id="myAdvisor1" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor" >
<property name="advice" ref="myMethodBeforeAdvice"/>
<property name="mappedName" value="doSome"/>
</bean>
<bean id="myAdvisor2" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor" >
<property name="advice" ref="myAfterReturningAdvice"/>
<property name="mappedName" value="doSome"/>
</bean>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
</beans>
4.测试
public final class TestMethodBeforeAdvice {
@Test
public void test01(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
IService proxy = (IService) ac.getBean("studentServiceImpl");
proxy.doOther();
proxy.doSome();
IService proxy1 = (IService) ac.getBean("teacherServiceImpl");
proxy1.doOther();
proxy1.doSome();
}
}
BeanNameAutoProxyCreator演示
其余同上
主配置文件
<?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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 注册目标类 -->
<bean id="studentServiceImpl" class="com.bjsxt.service.StudentServiceImpl"/>
<bean id="teacherServiceImpl" class="com.bjsxt.service.TeacherServiceImpl"/>
<!-- 注册前置通知 -->
<bean id="myMethodBeforeAdvice" class="com.bjsxt.advice.MyMethodBeforeAdvice"/>
<!-- 注册后置通知 -->
<bean id="myAfterReturningAdvice" class="com.bjsxt.advice.MyAfterReturingAdvice"/>
<!-- 注册顾问 -->
<bean id="myAdvisor1" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor" >
<property name="advice" ref="myMethodBeforeAdvice"/>
<property name="mappedName" value="doSome"/>
</bean>
<bean id="myAdvisor2" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor" >
<property name="advice" ref="myAfterReturningAdvice"/>
<property name="mappedName" value="doSome"/>
</bean>
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" value="studentServiceImpl"/>
<property name="interceptorNames" value="myAdvisor2"/>
</bean>
</beans>
Student目标类主业务逻辑当中doOther()方法执行!
Student目标类主业务逻辑当中doSome()方法执行!
后置通知方法执行! 目标方法返回值:null
Teacher目标类主业务逻辑当中doOther()方法执行!
Teacher目标类主业务逻辑当中doSome()方法执行!