目录
一、代理模式和静态代理
代理:为目标对象提供(包装)了一个代理,这个代理可以控制对目标对象的访问。
静态代理:
- 代理对象持有目标对象的句柄;
- 所有调用目标对象的方法,都调用代理对象的方法;
- 对每个方法,需要静态编码(理解简单,但代码繁琐)(所以当方法过多时最好使用动态代理)
- 一般代理对象和目标对象引用同一个接口
静态代理示例:
1.实现接口
public interface Subject{
public void request();
}
2.目标对象
class SubjectImpl implements Subject{
public void request(){
System.out.println("I am dealing the request.");
}
}
3.代理对象
class StaticProxy implements Subject{
//实际目标对象
private Subject subject;
public StaticProxy(Subject subject){
this.subject = subject;
}
public void request(){
System.out.println("PreProcess");
subject.request();
System.out.println("PostProcess");
}
}
4.静态代理实现
public class StaticProxyDemo {
public static void main(String args[]){
//创建实际对象
SubjectImpl subject = new SubjectImpl();
//把实际对象封装到代理对象中
StaticProxy p = new StaticProxy(subject);
p.request();
}
}
二、动态代理
动态代理:
- 对目标对象的方法每次被调用,进行动态拦截。(可以看作能动态生成代理对象)
代理处理器:
- 持有目标对象的句柄
- 实现InvocationHandler接口
1.接口:
public interface Subject{
public void request();
}
2.目标对象:
class SubjectImpl implements Subject{
public void request(){
System.out.println("I am dealing the request.");
}
}
3.代理处理器:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 代理类的调用处理器
*/
class ProxyHandler implements InvocationHandler{
private Subject subject;
public ProxyHandler(Subject subject){
this.subject = subject;
}
//此函数在代理对象调用任何一个方法时都会被调用。
@Override
public Object invoke(Object proxy, Method method, Object[] args)//代理类 , 方法, 形参
throws Throwable {
System.out.println(proxy.getClass().getName());
//定义预处理的工作,当然你也可以根据 method 的不同进行不同的预处理工作
System.out.println("====before====");
Object result = method.invoke(subject, args);//调用真实的方法
System.out.println("====after====");
return result;
}
}
4.动态代理模式:
中的第三步动态生成代理对象。会根据给定的接口,由Proxy类自动生成的对象;类型com.sun.proxy.$Proxy(),继承自java.lang.reflect.Proxy;通常和目标对象实现同样的接口(可以另外实现其他接口)
import java.lang.reflect.Proxy;
//动态代理模式
public class DynamicProxyDemo {
public static void main(String[] args) {
//1.创建目标对象
SubjectImpl realSubject = new SubjectImpl();
//2.创建调用处理器对象
ProxyHandler handler = new ProxyHandler(realSubject);
//3.动态生成代理对象
Subject proxySubject =
(Subject)Proxy.newProxyInstance(SubjectImpl.class.getClassLoader(),SubjectImpl.class.getInterfaces(), handler);
//proxySubject真实类型com.sun.proxy.$Proxy0
//proxySubject继承Proxy类,实现Subject接口
//newProxyInstance的第二个参数,就是指定代理对象的接口
//4.客户端通过代理对象调用方法
//本次调用将自动被代理处理器的invoke方法接收
proxySubject.request();
System.out.println(proxySubject.getClass().getName());
System.out.println(proxySubject.getClass().getSuperclass().getName());
}
}
注意:如果代理对象实现多个接口,一定要注意接口的排序,当多个接口有同名的方法,则默认以前面匹配的接口的方法调用。
此处示例代码相当于把上面代码的第三步动态生成代理对象分解成两步,从而实现多个接口。
ClassLoader cl = MultipleInterfacesProxyTest.class.getClassLoader();//类加载器
Class<?> proxyClass = Proxy.getProxyClass(cl, new Class<?>[]{Driver.class,Cook.class});
//生成代理对象
Object proxy = proxyClass.getConstructor(new Class[]{InvocationHandler.class}).
newInstance(new Object[]{handler});
三、AOP编程
aop:面向切面编程。
解释:本来c1和c2函数是耦合的,c1需要在c2前执行,而面向切面编程则将c1和c2分离,并且设置aop.xml配置文件,在配置文件中规定c2执行前必须执行c1,这样的化就降低了耦合,并且如果后续代码需要改变时,只需要添加代码,修改aop.xml配置文件即可。
利用动态代理实现切面编程。
主要是在代理处理器中控制,并且用ResourceListener来实时监测aop.xml配置文件的修改。
示例
1.主函数
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Main {
public static void initXml(){
XmlReader.readXml("aops.xml");
ResourceListener.addListener("E:/java/source/PMOOC04-03/");//实时监听文件的改变
}
public static void main(String[] args) throws Exception{
Main.initXml();
Person action = new PersonImpl();
ProxyHandler mh = new ProxyHandler(action);
ClassLoader cl = Main.class.getClassLoader();//类加载器
Class<?> proxyClass = Proxy.getProxyClass(cl, new Class<?>[]{Person.class});
Person proxy = (Person) proxyClass.getConstructor(new Class[]{InvocationHandler.class}).
newInstance(new Object[]{mh});//生成代理对象
while(true)
{
proxy.eat();//代理对象调用方法
try{
Thread.sleep(3000);
}
catch(Exception e){
e.printStackTrace();
}
}
}
}
2.接口类
public interface Person {
void eat();
void washHand();
void bath();
}
3.目标类
public class PersonImpl implements Person {
public void eat() {
System.out.println("I am eating");
}
public void washHand() {
System.out.println("I am washing hands");
}
public void bath() {
System.out.println("I am bathing");
}
}
4.代理处理器
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;
public class ProxyHandler implements InvocationHandler {
static String beforeMethod = "";
static String afterMethod = "";
private Person receiverObject;
public ProxyHandler(Person object){
this.receiverObject = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//处理before方法
if(beforeMethod!=null&&beforeMethod.length()>0){
ClassLoader cl = ProxyHandler.class.getClassLoader();
Class<?> c = cl.loadClass(receiverObject.getClass().getName());
Method m=c.getMethod(beforeMethod);//获取目标方法处理前需要处理的方法
Object obj = c.newInstance();
m.invoke(obj);
}
//处理目标方法
Object result = method.invoke(receiverObject, args);
//处理after方法
if(afterMethod!=null&&afterMethod.length()>0){
method.invoke(receiverObject, args);
ClassLoader cl = ProxyHandler.class.getClassLoader();
Class<?> c = cl.loadClass(receiverObject.getClass().getName());
Method m=c.getMethod(afterMethod);
Object obj = c.newInstance();
m.invoke(obj);
}
return result;
}
}
5.实时检查配置文件类
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ResourceListener {
private static ExecutorService fixedThreadPool=Executors.newCachedThreadPool();
private WatchService ws;
private String listenerPath;
private ResourceListener(String path){
try
{
ws=FileSystems.getDefault().newWatchService();
this.listenerPath=path;
}
catch (Exception e)
{
e.printStackTrace();
}
}
private void start(){
fixedThreadPool.execute(new Listener(ws, listenerPath));
}
public static void addListener(String path){
try{
ResourceListener resourceListener=new ResourceListener(path);
Path p=Paths.get(path);
p.register(resourceListener.ws, StandardWatchEventKinds.ENTRY_MODIFY,StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.ENTRY_CREATE);
resourceListener.start();
}
catch (Exception e){
e.printStackTrace();
}
}
class Listener implements Runnable{
WatchService ws;
String listenerPath;
Listener(WatchService ws,String listenerPath){
this.ws = ws;
this.listenerPath = listenerPath;
}
@Override
public void run() {
try {
while(true){
WatchKey watchKey = ws.take();
List<WatchEvent<?>> watchEvents = watchKey.pollEvents();
for(WatchEvent<?> event : watchEvents){
String context = event.context().toString();//对象
String kind = event.kind().toString();//变更类型
if(context.equals("aops.xml")){
if(kind.equals("ENTRY_MODIFY")){
XmlReader.readXml(listenerPath+"/"+event.context());
}
}
}
watchKey.reset();
}
} catch (InterruptedException e) {
e.printStackTrace();
try {
ws.close();
} catch (Exception e1) {
}
}
}
}
}
6.读写xml文件类
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
public class XmlReader {
public static void readXml(String filePath){
String xml = load(filePath);
try{
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
Document document;
DocumentBuilder dbBuilder = dbFactory.newDocumentBuilder();
StringReader sr = new StringReader(xml);
InputSource is = new InputSource(sr);
document = dbBuilder.parse(is);
Element root = document.getDocumentElement();
findMethod(root.getChildNodes());
}
catch(Exception e){
e.printStackTrace();
}
}
public static void findMethod(NodeList elementList){
for (int i = 0; i < elementList.getLength(); i++) {
Node elementNode = elementList.item(i);
//System.out.println("allnode: "+elementNode.getNodeName());
if (elementNode.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) elementNode;
String name = element.getNodeName();
if(name.equalsIgnoreCase("aop")){
readMethod(element.getChildNodes());
}
else{
findMethod(element.getChildNodes());
}
}
}
}
private static void readMethod(NodeList elementList){
String methodName = "";
for (int i = 0; i < elementList.getLength(); i++) {
Node elementNode = elementList.item(i);
if (elementNode.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) elementNode;
String name = element.getNodeName();
if(name.equals("method")){
if(methodName==null||methodName.length()==0)methodName = element.getFirstChild().getTextContent();
}
else if(name.equals("type")){
String type = element.getFirstChild().getTextContent();
if(type.equals("after")){
ProxyHandler.afterMethod = methodName;
}
else{
ProxyHandler.beforeMethod = methodName;
}
}
}
}
}
private static String load(String path){
try{
File file = new File(path);
FileReader reader = new FileReader(file);
BufferedReader bReader = new BufferedReader(reader);
StringBuilder sb = new StringBuilder();
String s = "";
while ((s =bReader.readLine()) != null) {
sb.append(s + "\n");
//System.out.println(s);
}
bReader.close();
return sb.toString();
}
catch(Exception e){
e.printStackTrace();
}
return null;
}
}
参考中国大学mooc《java核心技术》
来源:CSDN
作者:CSU-Benjamin
链接:https://blog.csdn.net/weixin_43698704/article/details/104200490