spring中的动态代理和AOP

1.JDK动态代理

(1) 什么是动态代理?

代理类在程序运行时创建的代理方式。代理类不是java类定义好的,而是在运行时根据我们在java代码中的“指示”动态生成的。

2. JDK动态代理和CGLIB动态代理

(1) JDK动态代理和CGLIB动态代理的应用场景?

如果目标对象实现了接口,我们采用JDK动态代理
如果目标对象没有实现了接口,我们采用CGLIB动态代理

(2) 使用JDK动态代理和CGLIB动态代理的实现步骤?

JDK动态代理

	
		//定义目标对象
		SomeService target = new SomeServiceImpl();
		//定义目标对象的代理对象
		SomeService proxy = (SomeService)Proxy.newProxyInstance(target.getClass().getClassLoader()//目标类的类加载器
				, target.getClass().getInterfaces()//目标类实现的所有的接口
				, new InvocationHandler() {//调用处理器
					//proxy   代理对象
					//method  目标方法
					//args  目标方法参数
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						String result = (String) method.invoke(target, args);
							return result.toUpperCase();
						}
				});
		String result = proxy.doSome();
		System.out.println(result);

CGLIB动态代理
代理工厂类:

//1、cglib动态代理工厂
public class CglibProxyFactory implements MethodInterceptor{
	
	private SomeServiceImpl target;
	//3、添加构造方法
	public CglibProxyFactory(SomeServiceImpl target) {
		super();
		this.target = target;
	}
	
	public CglibProxyFactory() {
		super();
	}

	//2、创建cglib代理对象的方法
	public SomeServiceImpl proxyCreator(){
		//创建增强器对象
		Enhancer enhancer = new Enhancer();
		//指定父类(目标类)
		enhancer.setSuperclass(SomeServiceImpl.class);
		//指定回调接口对象
		enhancer.setCallback(this);
		//创建cglib代理对象
		return (SomeServiceImpl) enhancer.create();
	}
	//4、重写intercrpt方法,对目标对象进行增强
	@Override
	public String intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		String result = (String) method.invoke(target, args);
		return result.toUpperCase();
	}
	
}

测试类


public class SomeTest {
	public static void main(String[] args) {
		//定义目标对象
		SomeServiceImpl target = new SomeServiceImpl();
		//定义目标对象的代理对象
		SomeServiceImpl proxy = new CglibProxyFactory(target).proxyCreator();
		System.out.println(proxy.doSome());
	}
}

4. 基于Schema-based方式之前置通知

(1) 如何搭建AOP编程环境?

在这里插入图片描述

(2) 如何创建前置通知?

配置文件
<?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="someServiceImpl" class="com.bjsxt.service.impl.SomeServiceImpl"></bean>
	<!-- 注册切面,前置通知 -->
	<bean id="myMethodBeforeAdvice" class="com.bjsxt.aspects.MyMethodBeforeAdvice"></bean>
	<!-- 注册切面,后置通知 -->
	<bean id="myAfterReturningAdvice" class="com.bjsxt.aspects.MyAfterReturningAdvice"></bean>
	<!-- 注册代理 -->
	<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
		<!-- 指定目标对象 -->
		<property name="target" ref="someServiceImpl"></property>
		<!-- 指定目标类的实现的所有接口 -->
		<property name="interfaces" value="com.bjsxt.service.SomeService"></property>
		<!-- 指定切面 -->
		<property name="interceptorNames" value="myMethodBeforeAdvice"></property>
	</bean>
</beans>
前置通知类:
package com.bjsxt.aspects;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class MyMethodBeforeAdvice implements MethodBeforeAdvice{
	
	/**
	 * method 目标方法
	 * args  目标方法参数列表
	 * target目标对象
	 *
	 */
	@Override
	public void before(Method method, Object[] args, Object target) throws Throwable {
		System.out.println("前置通知的before()方法执行了");
		
	}

}

5. 基于Schema-based方式之后置通知

(1) 基于Schema-based方式之后置通知

package com.bjsxt.aspects;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;

public class MyAfterReturningAdvice implements AfterReturningAdvice {

	@Override
	public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
		System.out.println("后置通知方法MyAfterReturningAdvice.afterReturning()执行"+returnValue);
		if(returnValue!=null){
			System.out.println("后置通知方法执行"+((String)returnValue).toUpperCase());
		}
	}

}

(2) 在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"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd">
	<!-- 注册目标类-->	
   	<bean id="someServiceImpl" class="com.bjsxt.service.impl.SomeServiceImpl"></bean>
	<!-- 注册切面,前置通知 -->
	<bean id="myMethodBeforeAdvice" class="com.bjsxt.aspects.MyMethodBeforeAdvice"></bean>
	<!-- 注册切面,后置通知 -->
	<bean id="myAfterReturningAdvice" class="com.bjsxt.aspects.MyAfterReturningAdvice"></bean>
	<!-- 注册代理 -->
	<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
		<!-- 指定目标对象 -->
		<property name="target" ref="someServiceImpl"></property>
		<!-- 指定目标类的实现的所有接口 -->
		<property name="interfaces" value="com.bjsxt.service.SomeService"></property>
		<!-- 指定切面 -->
		<property name="interceptorNames" value="myAfterReturningAdvice"></property>
	</bean>
</beans>

6. 基于Schema-based方式之环绕通知

(1) 如何创建环绕通知?

package com.bjsxt.aspects;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

//切面,环绕通知
public class MyMethodInterceptor implements MethodInterceptor {
	/**
	 *invacation  方法调用器  
	 */
	@Override
	public Object invoke(MethodInvocation invacation) throws Throwable {
		System.out.println("环绕通知:目标方法执行之前");
		Object result = invacation.proceed();
		if(result!=null){
			result = ((String)result).toUpperCase();
		}
		System.out.println("环绕通知:目标方法执行之后");
		
		return result;
	}

}

(2) 环绕通知是否能调用目标方法,如果可以,通过哪个对象调用?

通过invacation 方法调用器来调用目标方法

7. 基于Schema-based方式之异常通知

(1) 如何创建异常通知?

package com.bjsxt.aspects;

import org.springframework.aop.ThrowsAdvice;

public class MyThrowsAdvice implements ThrowsAdvice {
	public void afterThrowing(Exception ex){
		System.out.println("异常通知执行");
	}
}

(2) 异常通知能否获得异常信息,需要如何配置?

在目标方法中添加异常信息
比如 / by zero

package com.bjsxt.service.impl;

import com.bjsxt.service.SomeService;

public class SomeServiceImpl implements SomeService {

	@Override
	public void doSome() {
		System.out.println("SomeServiceImpl.doSome()方法执行"+1/0);
	}

	@Override
	public String doOther() {
		System.out.println("SomeServiceImpl.doOther()方法执行");
		return "love";
	}

}

添加配置文件:

<?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="someServiceImpl" class="com.bjsxt.service.impl.SomeServiceImpl"></bean>
	<!-- 注册切面,前置通知 -->
	<bean id="myMethodBeforeAdvice" class="com.bjsxt.aspects.MyMethodBeforeAdvice"></bean>
	<!-- 注册切面,后置通知 -->
	<bean id="myAfterReturningAdvice" class="com.bjsxt.aspects.MyAfterReturningAdvice"></bean>
	<!-- 注册切面,环绕通知 -->
	<bean id="myMethodInterceptor" class="com.bjsxt.aspects.MyMethodInterceptor"></bean>
	<!-- 注册切面,异常通知 -->
	<bean id="myThrowsAdvice" class="com.bjsxt.aspects.MyThrowsAdvice"></bean>
	<!-- 注册代理 -->
	<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
		<!-- 指定目标对象 -->
		<property name="target" ref="someServiceImpl"></property>
		<!-- 指定目标类的实现的所有接口 -->
		<property name="interfaces" value="com.bjsxt.service.SomeService"></property>
		<!-- 指定切面 -->
		<property name="interceptorNames" value="myThrowsAdvice"></property>
	</bean>
</beans>

8.基于AspectJ方式

(1)描述Spring、AspectJ和AOP三者之间的关系?

在这里插入图片描述

(2)AspectJ支持的通知常见有哪些?

前置通知、后置通知、环绕通知、异常通知和最终通知

9基于AspectJ方式之环境搭建

(1)导入jar包

在这里插入图片描述

(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: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">
	
</beans>

10基于AspectJ方式之注解方式

1、目标接口

package com.bjsxt.service;

public interface SomeService {
	void doSome();
	String doOther();
}

2、目标接口的实现类

package com.bjsxt.service.impl;

import com.bjsxt.service.SomeService;

public class SomeServiceImpl implements SomeService {

	@Override
	public void doSome() {
		//System.out.println("SomeServiceImpl.doSome()方法执行"+1/0);
		System.out.println("SomeServiceImpl.doSome()方法执行");
	}

	@Override
	public String doOther() {
		System.out.println("SomeServiceImpl.doOther()方法执行");
		return "love";
	}

}

3、定义切面类

package com.bjsxt.aspects;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
//切面
@Aspect//表名当前类是一个切面
public class MyAspect {
	//该注解表明当前方法是前置通知方法
	@Before("execution(* *..service.*.doSome(..))")
	public void before(){
		System.out.println("前置通知方法执行");
	}
	//该注解表明当前方法是后置通知方法
	@AfterReturning(value="execution(* *..service.*.doOther(..))",returning="result")
	public void afterReturning(Object result){
		System.out.println("后置通知方法执行,返回结果是:"+result);
	}
	//该注解表明当前方法是环绕通知方法
	@Around("execution(* *..service.*.doOther(..))")
	public Object around(ProceedingJoinPoint pjp) throws Throwable{
		System.out.println("环绕通知:目标方法执行之前");
		String result = (String) pjp.proceed();
		if(result!=null){
			result = result.toUpperCase();
		}
		System.out.println("环绕通知:目标方法执行之后");
		return result;
	}
	//该注解表明当前方法是异常通知方法
	@AfterThrowing(value="execution(* *..service.*.doSome(..))",throwing="ex")
	public void throwing(Exception ex){
		System.out.println("异常通知方法执行!异常通知信息为:"+ex);
	}
	//该注解表明当前方法是最终通知方法
	@After("execution(* *..service.*.doSome(..))")
	public void after(){
		System.out.println("最终通知方法执行");
	}
}

4、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="someServiceImpl" class="com.bjsxt.service.impl.SomeServiceImpl"></bean>
	<!-- 注册切面 -->
	<bean id="myAspect" class="com.bjsxt.aspects.MyAspect"></bean>
	<!-- 注册自动代理 -->
	<aop:aspectj-autoproxy/>
</beans>

5、测试类

package com.bjsxt.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.bjsxt.service.SomeService;

public class SomeTest {

	@Test
	public void someTest01(){
		
		ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
		SomeService someService = (SomeService) ac.getBean("someServiceImpl",SomeService.class);	
		someService.doSome();
		System.out.println(someService.doOther());
	}
	
}

注意:测试时五种通知分开测试,先注释掉其他四种,其中包括配置文件与切面类的注释。

11基于AspectJ方式之XML方式

1、2、5与基于AspectJ方式之注解方式相同省略

3、定义切面类

package com.bjsxt.aspects;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class MyAspect {
	//无参前置方法
	public void before(){
		System.out.println("前置通知方法执行");
	}
	//带参前置方法
	public void before(JoinPoint jp){
		System.out.println("前置通知方法执行!jp="+jp);
	}
	
	
	public void afterReturning(Object result){
		System.out.println("后置通知方法执行,返回结果是:"+result);
	}
	
	public Object around(ProceedingJoinPoint pjp) throws Throwable{
		System.out.println("环绕通知:目标方法执行之前");
		String result = (String) pjp.proceed();
		if(result!=null){
			result = result.toUpperCase();
		}
		System.out.println("环绕通知:目标方法执行之后");
		return result;
	}
	
  	public void throwing(Exception ex){
		System.out.println("异常通知方法执行!异常通知信息为:"+ex);
	}
	public void after(){
		System.out.println("最终通知方法执行");
	}
}

4、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="someServiceImpl" class="com.bjsxt.service.impl.SomeServiceImpl"></bean>
	<!-- 注册切面 -->
	<bean id="myAspect" class="com.bjsxt.aspects.MyAspect"></bean>
	<!-- AOP配置 -->
	<aop:config>
		<!-- 定义切入点 -->
		<aop:pointcut expression="execution(* *..service.*.doSome(..))" id="doSomePC"/>
		<aop:pointcut expression="execution(* *..service.*.doOther(..))" id="doOtherPC"/>
		<!-- 切面 -->
		<aop:aspect ref="myAspect">
			<!-- <aop:before method="before" pointcut-ref="doSomePC"/> -->
			<!-- <aop:before method="before(org.aspectj.lang.JoinPoint)" pointcut-ref="doSomePC"/> -->
			<aop:after-returning method="afterReturning(java.lang.Object)" pointcut-ref="doOtherPC" returning="result"/>
			<!-- <aop:around method="around" pointcut-ref="doOtherPC"/> -->
			<!-- <aop:after-throwing method="throwing(java.lang.Exception)" pointcut-ref="doSomePC" throwing="ex"/> -->
			<!-- <aop:after method="after" pointcut-ref="doSomePC"/> -->
		</aop:aspect>
	</aop:config>
</beans>
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值