自动代理
在前面的案例中,所有目标对象(Target Bean)的代理对象(Proxy Bean)都是在 XML 配置中通过 ProxyFactoryBean 创建的。
但在实际开发中,一个项目中往往包含非常多的 Bean, 如果每个 Bean 都通过 ProxyFactoryBean 创建,那么开发和维护成本会十分巨大。
为了解决这个问题,Spring 为我们提供了自动代理机制。
Spring 提供的自动代理方案,都是基于后处理 Bean 实现的,即在 Bean 创建的过程中完成增强,并将目标对象替换为自动生成的代理对象。
通过 Spring 的自动代理,我们在程序中直接拿到的 Bean 就已经是 Spring 自动生成的代理对象了。
Spring 为我们提供了 3 种自动代理方案:
- BeanNameAutoProxyCreator:根据 Bean 名称创建代理对象。
- DefaultAdvisorAutoProxyCreator:根据 Advisor 本身包含信息创建代理对象。
- AnnotationAwareAspectJAutoProxyCreator:基于 Bean 中的 AspectJ 注解进行自动代理对象。
本节我们就通过两个简单的实例,对 BeanNameAutoProxyCreator 和 DefaultAdvisorAutoProxyCreator 进行演示,至于 AnnotationAwareAspectJAutoProxyCreator,我们会在后续的教程中进行讲解。
=================================================================================================
根据 Bean 名称创建代理对象
项目依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>ssw</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.6</version>
</dependency>
</dependencies>
</project>
创建userdao接口:
package org.example.dao;
public interface UserDao {
public void add();
public void delete();
public void modify();
public void get();
}
实现userdao接口:
package org.example.dao.impl;
import org.example.dao.UserDao;
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("正在执行 UserDao 的 add() 方法……");
}
@Override
public void delete() {
System.out.println("正在执行 UserDao 的 delete() 方法……");
}
@Override
public void modify() {
System.out.println("正在执行 UserDao 的 modify() 方法……");
}
@Override
public void get() {
System.out.println("正在执行 UserDao 的 get() 方法……");
}
}
创建orderdao类:
package org.example.dao;
public class OrderDao {
public void add() {
System.out.println("正在执行 OrderDao 的 add() 方法……");
}
public void adds() {
System.out.println("正在执行 OrderDao 的 adds() 方法……");
}
public void delete() {
System.out.println("正在执行 OrderDao 的 delete() 方法……");
}
public void modify() {
System.out.println("正在执行 OrderDao 的 modify() 方法……");
}
public void get() {
System.out.println("正在执行 OrderDao 的 get() 方法……");
}
}
创建UserDaoBeforeAdvice类:
package org.example.advice;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
/**
* 增强代码
* MethodBeforeAdvice 前置增强
*
* @author c语言中文网 c.biancheng.net
*/
public class UserDaoBeforeAdvice implements MethodBeforeAdvice
{
@Override
public void before(Method method, Object[] args, Object target) throws Throwable
{
System.out.println("正在执行前置增强操作…………");
}
}
创建OrderDaoAroundAdvice类:
package org.example.advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
* 增强代码
* 环绕增强
*
* @author c语言中文网 c.biancheng.net
*/
public class OrderDaoAroundAdvice implements MethodInterceptor
{
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable
{
System.out.println("环绕增强前********");
//执行被代理对象中的逻辑
Object result = methodInvocation.proceed();
System.out.println("环绕增强后********");
return result;
}
}
创建bean.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.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 定义目标(target)对象 -->
<bean id="userDao" class="org.example.dao.impl.UserDaoImpl"></bean>
<bean id="orderDao" class="org.example.dao.OrderDao"></bean>
<!-- 定义增强 -->
<bean id="beforeAdvice" class="org.example.advice.UserDaoBeforeAdvice"></bean>
<bean id="aroundAdvice" class="org.example.advice.OrderDaoAroundAdvice"></bean>
<!--Spring 自动代理:根据 Bean 名称创建代理独享-->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" value="*Dao"></property>
<property name="interceptorNames" value="beforeAdvice,aroundAdvice"></property>
</bean>
</beans>
执行代码:
package org.example;
import org.example.dao.OrderDao;
import org.example.dao.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main
{
public static void main(String[] args)
{
//获取 ApplicationContext 容器
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//获取代理对象
UserDao userDao = context.getBean("userDao", UserDao.class);
//获取代理对象
OrderDao orderDao = context.getBean("orderDao", OrderDao.class);
//调用 UserDao 中的各个方法
userDao.add();
userDao.delete();
userDao.modify();
userDao.get();
//调用 OrderDao 中的各个方法
orderDao.add();
orderDao.adds();
orderDao.delete();
orderDao.get();
orderDao.modify();
}
}
执行结果:
-------------------------------------------------------------------------------------------------------------------------------------
=========================================================================================
根据切面中信息创建代理对象
修改bean.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.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 定义目标(target)对象 -->
<bean id="userDao" class="org.example.dao.impl.UserDaoImpl"></bean>
<bean id="orderDao" class="org.example.dao.OrderDao"></bean>
<!-- 定义增强 -->
<bean id="beforeAdvice" class="org.example.advice.UserDaoBeforeAdvice"></bean>
<bean id="aroundAdvice" class="org.example.advice.OrderDaoAroundAdvice"></bean>
<!--定义切面-->
<bean id="myPointCutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<!--定义表达式,规定哪些方法进行拦截 .* 表示所有方法-->
<!--<property name="pattern" value=".*"></property>-->
<property name="patterns" value="org.example.dao.OrderDao.add.*,org.example.dao.OrderDao.delete.*"></property>
<property name="advice" ref="aroundAdvice"></property>
</bean>
<!--Spring 自动代理:根据切面 myPointCutAdvisor 中信息创建代理对象-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
</beans>
执行结果:
-------------------------------------------------------------------------------------------------------------------------------------------