Spring(十)spring编写代理(aop编程)
原创
©著作权归作者所有:来自51CTO博客作者scx_white的原创作品,请联系作者获取转载授权,否则将追究法律责任
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编写代理(全自动)
全自动和半自动相比较在于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();
}
运行结果: