Spring提供了对对象进行AOP编程.Spring本身并不是AOP(简单来说就是spring能帮我们产生代理对象)
AOP:横向重复,纵向抽取.(Filter过滤器,Interceptor拦截器,Proxy动态代理)
spring实现aop的原理
动态代理
被代理的对象必须实现接口,才能产生代理对象.如果没有接口将不能使用动态代理技术
public class UserServiceProxyFactory {
private UserService service;
public UserServiceProxyFactory(UserService service) {
super();
this.service = service;
}
public UserService getUserServiceProxy(){
UserService us = (UserService) Proxy.newProxyInstance(this.getClass().getClassLoader(),UserServiceImpl.class.getInterfaces(),new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("start transaction");
Object invoke = method.invoke(service, args);
System.out.println("commit transaction");
return invoke;
}
});
return us;
}
}
cglib代理
第三方代理技术,可以对任何类进行代理.代理的原理是对被代理对象进行继承.如果目标对象被final对象修饰,那么该类将无法被cglib代理
public class UserProxyFactory {
public UserService getUserServiceProxy() {
Enhancer en = new Enhancer(); // 生成代理对象
en.setSuperclass(UserServiceImpl.class);
en.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] arg2, MethodProxy proxy) throws Throwable {
System.out.println("start transaction");
Object invokeSuper = proxy.invokeSuper(obj, arg2);
System.out.println("commit transaction");
return invokeSuper;
}
});
UserService obj = (UserService) en.create();
return obj;
}
}
那么spring是使用了哪一个技术呢?
两种都使用了,根据情况来决定使用了哪一种技术,如果目标对象有接口就优先使用动态代理技术,如果没有接口就使用cglib代理
动态代理强调的是接口,cglib代理强调的是对目标对象的继承.
Spring中的aop名词
名词 | 含义 |
---|---|
joinpoint(连接点) | 目标对象中,所有可以增强的方法 |
Pointcut(切入点) | 目标对象,已经被增强的方法 |
Advice(通知/增强) | 增强的代码 |
Target(目标) | 被代理的对象 |
Weaving(织入) | 将通知应用到切入点的过程 |
Proxy (代理) | 将通知织入目标对象之后,形成代理对象 |
aspect(切面) | 切入点+通知 |
Spring-Aop的配置(xml配置)
1. 导包&&导入约束
- 基础4个组件包+2个日志包+
spring-aspects-4.2.4.RELEASE.jar

spring-aop-4.2.4.RELEASE.jar

com.springsource.org.aopalliance-1.0.0.jar

com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

- 导入约束
约束文件:spring-aop-4.2.xsd
前缀为:aop

2. 准备目标对象
填写要被代理的目标对象.
3. 准备通知(advice)
准备增强的代码

4. 配置进行织入,将通知应用到切入点的过程
- 配置目标对象
<bean name="UserService" class="com.demo.service.UserServiceImpl"></bean>
- 配置通知
<bean name="MyAdvice" class="com.demo.aspect.MyAdvice"></bean>
- 配置切入点
<aop:config>
<aop:pointcut expression="execution(* com.demo.service.*ServiceImpl.*(..))" id="pc"/>
<aop:aspect ref="MyAdvice">
<aop:after method="after" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
- 切入点表达式
execution(表达式) 表达式: [方法访问修饰符] 方法返回值 包名.类名.方法名(方法的参数)
public * cn.demo.spring.dao.*.*(..)
* cn.demo.spring.dao.*.*(..)
* cn.demo.spring.dao.UserDao+.*(..)
* cn.demo.spring.dao..*.*(..)
Spring-aop(注解配置)
@EnableAspectJAutoProxy注解:开启aop支持,相当于xml文件中的aop:aspectj-autoproxy</aop:aspectj-autoproxy>标签
配置文件
<!-- <context:component-scan base-package="com.demo.service"></context:component-scan> -->
<!--1. config the target -->
<bean name="UserService" class="com.demo.service.UserServiceImpl"></bean>
<!--2. config the advice -->
<bean name="myAdvice" class="com.demo.aspect.MyAdvice"></bean>
<!--3. config the Pointcut 开启spring对aop注解的支持 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
通知类
@Aspect
public class MyAdvice {
@Pointcut("execution(* com.demo.service.*ServiceImpl.*(..))")
public void pc(){}
@Before("MyAdvice.pc()")
public void before() {
System.out.println("前置通知");
}
@After("MyAdvice.pc()")
public void after() {
System.out.println("后置通知");
}
@Around("MyAdvice.pc()")
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕通知前部分");
Object proceed = pjp.proceed();
System.out.println("环绕通知后部分");
}
public void beforeException() {
System.out.println("前置通知,就算出现异常也会调用");
}
public void afterException() {
System.out.println("后置通知,就算出现异常也会调用");
}
}