Spring代理+通知

一.23设计模式之代理模式

组成:

抽象角色:通过接口或抽象类声明真实角色的业务方法。

代理角色:实现抽象角色,是真实角色的代理,通过真实角色业务逻辑来实现抽象的方法,也可以附加自己的操作。

真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。

首先来看看Java的代理模式:

1.静态代理

package com.zking.spring02.staticproxy;

/**
 * 
* @ClassName: IPerson
* @Description: 抽象角色
* @author 夏
* @date 2018年9月18日 下午2:35:33
*
 */
public interface IPerson {
	/**
	 * 
	* @Title: dance
	* @Description: 跳舞的方法
	* @return void
	 */
	public void dance();
	
}
package com.zking.spring02.staticproxy;

/**
 * 
* @ClassName: Proxy
* @Description: 抽象代理
* @author 夏
* @date 2018年9月18日 下午2:35:53
*
 */
public class Proxy  implements IPerson{

	//定义接口对象
	private IPerson p;
	
	public Proxy(IPerson p) {
		super();
		this.p = p;
	}

/**
 * 实现接口方法
 */
	public void dance() {
    p.dance();	
	}
	
	
	
	
	
	
	

}
package com.zking.spring02.staticproxy;

/**
 * 
* @ClassName: Person
* @Description: 真实角色
* @author 夏
* @date 2018年9月18日 下午2:35:21
*
 */
public class Person implements IPerson {

/**
 * 实现跳舞的方法
 */
	public void dance() {
	System.out.println("dance");
	}

}
package com.zking.spring02.staticproxy;

/**
 * 
* @ClassName: Test
* @Description: 测试类
* @author 夏
* @date 2018年9月18日 下午2:41:35
*
 */
public class Test {
	public static void main(String[] args) {
		//定义真实角色对象
		Person p=new Person();
		IPerson ip=new Proxy(p);
	    ip.dance();
		
	}
	


	
	
	
}

可以这样理解,抽象角色声明我真实角色的业务行为,然后代理去实现抽象角色,也就是去接这个这个业务,接到这个业务后,然后由真实角色去实现这个行为。

2.java动态代理

package com.zking.spring02.dynamicproxy;

/**
 * 
* @ClassName: IPerson
* @Description: 抽象角色
* @author 夏
* @date 2018年9月18日 下午2:35:33
*
 */
public interface IPerson {
	
	/**
	 * 
	* @Title: dance
	* @Description: 业务行为接口方法
	* @return void
	 */
	public void dance();
	
}
package com.zking.spring02.dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;



/**
 * 
* @ClassName: Proxy
* @Description: 抽象代理
* @author 夏
* @date 2018年9月18日 下午2:35:53
*
 */
public class Proxy  implements InvocationHandler{   

	//定义接口对象
	private IPerson ip;

	public Proxy(IPerson ip) {
		super();
		this.ip = ip;
	}

/**
 * 实现方法
 */
	public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {
		return arg1.invoke(ip, arg2);
	}


	
	
	
	
	
	
	

}
package com.zking.spring02.dynamicproxy;

/**
 * 
* @ClassName: Person
* @Description: 真实角色
* @author 夏
* @date 2018年9月18日 下午2:35:21
*
 */
public class Person implements IPerson {
/**
 * 实现接口方法
 */
	public void dance() {
	System.out.println("dance");
	}

}
package com.zking.spring02.dynamicproxy;


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;



/**
 * 
* @ClassName: Test
* @Description: 测试类
* @author 夏
* @date 2018年9月18日 下午2:41:35
*
 */
public class Test {
	public static void main(String[] args) {
        //定义真实角色
		Person p=new Person();
		//代理真实角色
		InvocationHandler  invocationHandler=new com.zking.spring02.dynamicproxy.Proxy(p);
		//接口对象
		IPerson ip=(IPerson) Proxy.newProxyInstance(Person.class.getClassLoader(), Person.class.getInterfaces(), invocationHandler);
     
		ip.dance();
		
	}
	


	
	
	
}

java静态代理和动态代理的区别:

静态代理实现的是抽象角色的接口,每次接口类多增加一个方法,代理类就要去实现,如果程序规模大的话那么代码的复杂程度也就大,重复的代码也就多了。

动态代理实现的接口是InvocationHandler,实现的方法相当于接口里面的方法被集中处理,灵活性高,复读性强。

3.Spring代理

package com.zking.spring02.springproxy;

/**
 * 
* @ClassName: IPerson
* @Description: 抽象角色
* @author 夏
* @date 2018年9月18日 下午2:35:33
*
 */
public interface IPerson {
	
	public void dance();
	
}
package com.zking.spring02.springproxy;

/**
 * 
* @ClassName: Person
* @Description: 真实角色
* @author 夏
* @date 2018年9月18日 下午2:35:21
*
 */
public class Person implements IPerson {

	public void dance() {
	System.out.println("dance");
	}

}
<?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"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:util="http://www.springframework.org/schema/util"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd">

<!-- 配置目标 -->
<bean id="p" class="com.zking.spring02.springproxy.Person"></bean>

<!-- 配置混合代理 -->
<bean id="myProxy" class="org.springframework.aop.framework.ProxyFactoryBean">

<!-- 引入目标 -->
<property name="target" ref="p"></property>

<!-- 代理接口 -->
<property name="proxyInterfaces">
<list>
<!-- 接口 -->
<value>com.zking.spring02.springproxy.IPerson</value>
</list>
</property>



</bean>




</beans>
package com.zking.spring02.springproxy;

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

/**
 * 
* @ClassName: Test
* @Description: 测试类
* @author 夏
* @date 2018年9月18日 下午2:41:35
*
 */

public class Test {
	
	@org.junit.Test
public void SpringProxy() {
	ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
IPerson ip=	(IPerson) applicationContext.getBean("myProxy");
	ip.dance();
	
	}


	
	
	
}

这里我们可以清楚的看到,java类中已经没有了代理类了,这里的代理类是以一种xml配置的形式创建bean对象,代理的所有操作,在混合代理中已经实现了混合代理的bean对象中就包含了目标--真实角色,以及代理接口--抽象角色,实现原理大体一致,只是形式不同而已

二.Spring通知

Spring通知可分为:前置通知,后置通知,环绕通知。

Java类定义前置通知

package com.zking.spring02.advice;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

/**
 * 
* @ClassName: BeforeAdvice
* @Description:前置通知类
* @author 夏
* @date 2018年9月18日 下午3:51:48
*
 */
public class BeforeAdvice implements MethodBeforeAdvice{

	public void before(Method method, Object[] args, Object target) throws Throwable {
	System.out.println("前置通知");
	}

}

Java类定义后置通知

package com.zking.spring02.advice;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;

/**
 * 
* @ClassName: AfterAdvice
* @Description: 后置通知类
* @author 夏
* @date 2018年9月18日 下午10:46:07
*
 */
public class AfterAdvice implements AfterReturningAdvice{

	public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
	System.out.println("后置通知");
		
	}

}

Java类定义环绕通知

package com.zking.spring02.advice;


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


/**
 * 
* @ClassName: Interceptor
* @Description: 环绕通知类
* @author 夏
* @date 2018年9月18日 下午10:46:23
*
 */
public class Interceptor implements MethodInterceptor{

	public Object invoke(MethodInvocation invocation) throws Throwable {
		System.out.println("环绕通知");
		return invocation.proceed();
	}


}

在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:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:util="http://www.springframework.org/schema/util"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd">

<!-- 配置目标 -->
<bean id="p" class="com.zking.spring02.springproxy.Person"></bean>
<!-- 配置混合代理 -->
<bean id="myProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 引入目标 -->
<property name="target" ref="p"></property>
<!-- 代理接口 -->
<property name="proxyInterfaces">
<list>
<value>com.zking.spring02.springproxy.IPerson</value>
</list>
</property>

<!-- 引用通知 -->
<property name="interceptorNames">
<list>
<!-- 通知过滤 -->
<idref bean="myAdvisor"/>
<!-- 前置通知 -->
<idref bean="BeforeAdvice"/>
<!-- 后置通知 -->
<idref bean="AfterAdvice"/>
<!-- 环绕通知 -->
<idref bean="Interceptor"/>
</list>
</property>


</bean>

<!-- 配置前置通知 -->
<bean id="BeforeAdvice" class="com.zking.spring02.advice.BeforeAdvice"></bean>
<!-- 配置后置通知 -->
<bean id="AfterAdvice" class="com.zking.spring02.advice.AfterAdvice"></bean>
<!-- 配置环绕通知 -->
<bean id="Interceptor" class="com.zking.spring02.advice.Interceptor"></bean>

<!-- 配置通知过滤 -->
<bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="BeforeAdvice"></property>

<!-- 指定特有方法设置通知 -->
<property name="pattern" value=".*dance*."></property>
</bean>




</beans>

可以看到,每个通知的实现的接口都是不一样的,所以带来的效果也是不同的,使用通知的前提条件是,必须要在xml文件中配置相应的通知,然后代理再去引用这些通知来达到想要的通知效果。

前置通知的位置在实现方法之前,那么一般我们可以用这个通知做编码格式转换,以及信息的加密,解密等。

后置通知的位置是在实现方法之后,那么这个通知我们可以做一个方法操作日志等。

那么环绕通知是在前置通知之后,它的return invocation.proceed(),可以决定该方法是否继续执行,这里的话我们可以做一个业务逻辑的判断。

猜你喜欢

转载自blog.csdn.net/Mr_xiayijie/article/details/82764868
今日推荐