一.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>