Spring(八)jdk动态代理(AOP简单实现)

Spring(九)CGLIB字节码增强
这两篇文章写了两种方式的手动生成代理。我们应该如何使用spring自动生成代理呢

spring编写代理(半自动)

我们首先使用spring来模拟我们自己生成的代理步骤即半自动

目标类

public interface UserService {
public void addUser();
public void updateUser();
public void deleteUser();
}

切面类

切面类中确定通知,需要实现不同接口,接口就是规范,从而就确定方法名称。
采用“环绕通知” MethodInterceptor

public class MyAspect implements MethodInterceptor{

@Override
public Object invoke(MethodInvocation mi) throws Throwable {
System.out.println("前方法");
Object obj=null;
//执行目标类
obj=mi.proceed();
System.out.println("后方法");
return

spring配置

在创建代理类时,使用工厂bean factorybean 底层调用getObject返回特殊bean
proxyFactoryBean用于创建代理工厂bean 生成特殊代理对象。
interfaces : 确定接口们
通过可以设置多个值
只有一个值时,可以使用value=””
target : 确定目标类
interceptorNames : 通知 切面类的名称,类型String[],如果设置一个值 value=””
在上两篇文章中我们分别使用了jdk动态代理和cglib动态代理
在spring中我们可以通过设置​​​<property name="optimize" value="true"></property>​​​ 强制使用cglib 而在不声明optimize时
spring底层将判断目标类是否有接口,如果没有接口 使用cglib字节码增强,否则使用jdk动态代理。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 创建目标类 -->
<bean id="userServiceId" class="com.scx.autoproxy.test.UserServiceImpl"></bean>
<!-- 创建切面类 -->
<bean id="myAspectId" class="com.scx.autoproxy.test.MyAspect"></bean>
<!-- 创建代理类-->
<bean id="proxyServiceId" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces" value="com.scx.autoproxy.test.UserService"></property>
<property name="target" ref="userServiceId"></property>
<property name="interceptorNames" value="myAspectId"></property>
</bean>
</beans>

测试

public void testProxy(){
String xmlPath="com/scx/autoproxy/test/applicationContext.xml";
ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath);
UserService userService=(UserService) applicationContext.getBean("proxyServiceId");
userService.addUser();
userService.updateUser();
userService.deleteUser();
}

运行结果:

Spring(十)spring编写代理(aop编程)_jdk动态代理

spring编写代理(全自动)

全自动和半自动相比较在于xml配置文件的代理类的编写
在半自动中,我们是通过模拟jdk动态代理的方式生成代理。在全自动中
使用aop命名空间实现。

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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 创建目标类 -->
<bean id="userServiceId" class="com.scx.autoproxy.test.copy.UserServiceImpl"></bean>
<!-- 创建切面类(通知) -->
<bean id="myAspectId" class="com.scx.autoproxy.test.copy.MyAspect"></bean>
<!-- 创建代理类-->
<aop:config proxy-target-class="true">
<aop:pointcut expression="execution(* com.scx.autoproxy.test.copy.*.*(..))" id="myPointCut"/>
<aop:advisor advice-ref="myAspectId" pointcut-ref="myPointCut"/>
</aop:config>
</beans>

在aop-config配置中,可以声明proxy-target-class=”true”使用cglib代理
aop:pointcut 切入点 从目标对象获得具体方法
aop:advisor 特殊的切面 只有一个通知和一个切入点
切入点表达式

execution(* com.scx.autoproxy.test.copy.*.*(..))
/*
解释如下:
execution选择方法
* 返回值任意
com.scx.autoproxy.test.copy 包名
* 类名任意
* 方法名任意
.. 参数任意
*/

测试

public void testProxy(){
String xmlPath="com/scx/autoproxy/test/copy/applicationContext.xml";
ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath);
UserService userService=(UserService) applicationContext.getBean("userServiceId");
userService.addUser();
userService.updateUser();
userService.deleteUser();
}

运行结果:

Spring(十)spring编写代理(aop编程)_xml_02