Spring-AOP(面向切面)

291 阅读3分钟

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

image

spring-aop-4.2.4.RELEASE.jar

image

com.springsource.org.aopalliance-1.0.0.jar

image

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

image

  • 导入约束

约束文件:spring-aop-4.2.xsd

前缀为:aop

image

2. 准备目标对象

填写要被代理的目标对象.

3. 准备通知(advice)

准备增强的代码

image

4. 配置进行织入,将通知应用到切入点的过程
  1. 配置目标对象
  <bean name="UserService" class="com.demo.service.UserServiceImpl"></bean>
  1. 配置通知
 <bean name="MyAdvice" class="com.demo.aspect.MyAdvice"></bean> 
  1. 配置切入点
  <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("后置通知,就算出现异常也会调用");
	}
}