Spring实现动态代理配置是有两种配置文件:
1、
2、
一、 AOP配置annotation方式
(一) 搭建annotation开发环境
首先:需要在配置文件中加入@AspectJ标签
<aop:aspectj-autoproxy/>
自动帮我产生代理
注意:Spring默认并没有加入aop的xsd文件,因为我们需要手动加入(红色部分)
<beansxmlns="http://www.springframework.org/schema/beans"
</beans>
(二) aspectJ类库
AspectJ是一个专门用来实现动态代理(AOP编程)的类库
AspectJ是面向切面编程的框架
Spring使用就是这个类库实现动态代理的
(三) AOP的annotation实例
要求:在执行save()方法之前加入日志逻辑
1、
2、
3、
importorg.aspectj.lang.annotation.Aspect;
importorg.aspectj.lang.annotation.Before;
importorg.springframework.stereotype.Component;
@Aspect
@Component
public classLogInterceptor {
}
(四)
三个连接点(切入点) |
1、
切入面 |
程序执行过程 |
2、
切入点人集合
当需要定义一个切入点时,则需要使用这个
@Pointcut("execution(* com.xyz.someapp.service.*.*(..))")
3、
切面
4、
切入点的逻辑
例如上例中的@Before
5、
被代理对象
6、
织入
(五) 织入点语法
1、
execution(public voidcom.wjt276.dao.impl.UserDaoImpl.save(com.wjt276.model.User))
2、
execution(public * *(..))
3、
execution(* set*(..))
4、
execution(* com.xyz.service.AccountService.*(..))
5、
execution(* com.xyz.service.*.*(..))
6、
execution(* com.xyz.service..*.*(..))
7、
execution(public void com.xyz.service..*.*(..))
execution(public !void com.xyz.service..*.*(..))
8、 args:这个用于获取拦截方法的参数
如:
/**
myMehod为一个切入点,切入点声明如下:
@Pointcut("execution(* com.test.aop.spring..*.*(..)) ")
public void myMethod(){}
**/
@Before(value = "myMethod() && args(name)")
public void before(String name){
System.out.println("前置通知" + name);
}
注意:这时这个前置通知只会拦截那些 只有一个String类型参数 的方法,其它的方法都不会被这个前置通知所拦截,并且方法的这个String参数也会作为before的参数传入
其它通知都有这个功能
9、 returning/throwing:分别为@AfterReturning与@AfterThrowing的属性
/**
pointcut:指定切入点
returning:将方法的返回值(返回值必须为String类型时)做为参数传入afterReturn方法;
只有1)被拦截方法的返回值类型与切入方法的参数一致或2)被拦截方法的声明为void时这两种情况才会被拦截.
throwing:将被拦截方法产生的异常做为参数传入afterThrowing方法,只有产生异常才会被这个切入点拦截;
且产生的异常为切入方法的异常参数的子类(下面的为Exception的子类,也就是所有的异常都会被拦截)
**/
@AfterReturning(pointcut="myMethod()", returning="result")
public void afterReturn(String result){
System.out.println("return通知" + result);
}
@AfterThrowing(pointcut = "myMethod()", throwing="e")
public void afterThrowing(Exception e){
System.out.println("异常通知" + e);
}
注意:以上是AspectJ的织入点语法,SpringAOP也实现了自己的织入点语法,同样可以使用
within(com.xyz.service.*)
within(com.xyz.service..*)
this(com.xyz.service.AccountService)
target(com.xyz.service.AccountService)
args(java.io.Serializable)
@target(org.springframework.transaction.annotation.Transactional)
@within(org.springframework.transaction.annotation.Transactional)
@annotation(org.springframework.transaction.annotation.Transactional)
@args(com.xyz.security.Classified)
bean(tradeService)
bean(*Service)
(六) Advice
1、 @Before
执行方法之前
@Aspect
public class BeforeExample {
@Aspect
public class BeforeExample {
2、 @ AfterReturning
方法正常执行完之后
@Aspect
public class AfterReturningExample {
@Aspect
public class AfterReturningExample {
3、 @ AfterThrowing
方法抛出异常之后
@Aspect
public class AfterThrowingExample {
@Aspect
public class AfterThrowingExample {
4、 @After (finally)
方法抛出异常被catch之后,需要进行的部分(相当于finally功能)
@Aspect
public class AfterFinallyExample {
5、 @ Around
在方法之前和之后都要加上
但是需要一个参数ProceedingJoinPoint,并者需要ObjectretVal = pjp.proceed();
和返回return retVal;
@Aspect
public class AroundExample {
(七) Pointcut
当多个Advice个有相同的织入点。那么我们可以定义一个织入点集合,在需要使用的地方,调用就可以了。
例如:
@Aspect
@Component
public classLogInterceptor {
注意:那个空方法,只是为了给Pointcut起个名字,以方便别处使用
(八) annotatin方式的AOP实例
importorg.aspectj.lang.ProceedingJoinPoint;
importorg.aspectj.lang.annotation.AfterReturning;
importorg.aspectj.lang.annotation.Around;
importorg.aspectj.lang.annotation.Aspect;
importorg.aspectj.lang.annotation.Before;
importorg.aspectj.lang.annotation.Pointcut;
importorg.springframework.stereotype.Component;
@Aspect
@Component
public classLogInterceptor {
return result;
}
配置xml方式
xml方式是我们以后使用的比较多的,因为当切面类我们没有源代码时、当我们使用第三方的切面类时,我就不能使用annotation的方式,而且如果使用annotation方式一但程序编译后就不可以修改了。如果使用xml方式就不一样了,我们只需要修改xml文件就可以了。
xml方式与annotation的作用是一样。现在就是实例:
<?xml version="1.0"encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
</beans>
1.基本配置:
<?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-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd "> <context:component-scan base-package="com.persia"> <!-- 开启组件扫描 --> </context:component-scan> <context:annotation-config> <!--开启注解处理器--> </context:annotation-config> <!-- 使用注解,省去了propertity的xml配置,减少xml文件大小 --> <bean id="personServiceAnno" class="com.persia.PersonServiceAnnotation"></bean> <bean id="personDaoBeanAnno" class="com.persia.PersonDaoBean"></bean> <bean id="personDaoBeanAnno2" class="com.persia.PersonDaoBean"></bean> <!-- 自动注解 --> <bean id="personServiceAutoInject" class="com.persia.PersonServiceAutoInject" autowire="byName"></bean> <bean id="personService" class="com.persia.PersonServiceBean"> <!-- 由spring容器去创建和维护,我们只要获取就可以了 --> </bean> <bean id="personService2" class="com.persia.PersonServiceBeanFactory" factory-method="createInstance" lazy-init="true" init-method="init" destroy-method="destory"> <!-- 静态工厂获取bean --> </bean> <bean id="fac" class="com.persia.PersonServiceBeanInsFactory"></bean> <bean id="personService3" factory-bean="fac" factory-method="createInstance" scope="prototype"> <!-- 实例工厂获取bean,先实例化工厂再实例化bean--> </bean> <!-- ref方式注入属性 --> <bean id="personDao" class="com.persia.PersonDaoBean"></bean> <bean id="personService4" class="com.persia.PersonServiceBean"> <property name="personDao" ref="personDao"></property> </bean> <!-- 内部bean方式注入 --> <bean id="personService5" class="com.persia.PersonServiceBean"> <property name="personDao"> <bean class="com.persia.PersonDaoBean"></bean> </property> <property name="name" value="persia"></property> <property name="age" value="21"></property> <property name="sets"> <!-- 集合的注入 --> <set> <value>第一个</value> <value>第二个</value> <value>第三个</value> </set> </property> <property name="lists"> <!-- 集合的注入 --> <list> <value>第一个l</value> <value>第二个l</value> <value>第三个l</value> </list> </property> <property name="properties"> <props> <prop key="key1">value1</prop> <prop key="key2">value2</prop> <prop key="key3">value3</prop> </props> </property> <property name="map"> <map> <entry key="key1" value="value-1"></entry> <entry key="key2" value="value-2"></entry> <entry key="key3" value="value-3"></entry> </map> </property> </bean> <bean id="personService6" class="com.persia.PersonServiceBean"> <constructor-arg index="0" value="构造注入的name" ></constructor-arg> <!-- 基本类型可以不写type --> <constructor-arg index="1" type="com.persia.IDaoBean" ref="personDao"> </constructor-arg> </bean> </beans>
2.开启AOP:
<?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" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd "> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <bean id="myInterceptor" class="com.persia.service.MyInterceptor"></bean> <bean id="personServiceImpl" class="com.persia.service.impl.PersonServiceImpl"></bean> </beans>
AOP的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" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd "> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <bean id="personService" class="com.persia.service.impl.PersonServiceImpl"></bean> <bean id="aspectBean" class="com.persia.service.MyInterceptor"></bean> <aop:config> <aop:aspect id="myaop" ref="aspectBean"> <aop:pointcut id="mycut" expression="execution(* com.persia.service.impl.PersonServiceImpl.*(..))"/>
<aop:pointcut id="argcut" expression="execution(* com.persia.service.impl.PersonServiceImpl.*(..)) and args(name)"/> <!-- args(name) 在xml中这样使用-->
<aop:before pointcut-ref="mycut" method="doAccessCheck" />
<aop:after-returning pointcut-ref="mycut" method="doAfterReturning"/>
<aop:after-throwing pointcut-ref="mycut" method="doThrowing"/>
<aop:after pointcut-ref="argcut" method="doAfter" arg-names="name"/>
<aop:around pointcut-ref="mycut" method="arround"/>
</aop:aspect>
</aop:config>
</beans>
实现动态代理注意
因为Spring要实现AOP(面向切面编程),需要加入切面逻辑的类就会生成动态代理。在动态代理类中加入切面类从而实现面向切面编程,但生成动态代理存在以下注意事项:
1、
2、