拦截System.out和System.err

System.out和System.err是Java的默认输出,大家对此都是非常熟悉的,但是你想过如何对他们进行拦截,而将输入转移到其他位置吗?

你可能想只需要对System.out和System.err做一个代理就好了,ok,就是这么回事,然后通过System.setOut和System.setErr方法将代理传给JVM,但是到底怎么做呢?因为他们的类型是java.io.PrintStream,是不是写一个类PrintStreamProxy代理所有的public方法就行了呢,如果你阅读了源代码的话会发现这样做会遇到很多问题,具体什么问题大家试一试就知道了,本文说的是另外一种代理。

因为java.io.PrintStream有一个是用java.OutputStream的构造方法,所有的输出最终都是通过OutputStream完成的,所有拦截它可以达到同样的效果。

下面就是代码了:

abstract class Monitor extends OutputStream {

		private PrintStream real;
		private List<Byte> buffer;

		private char lineChar;

		public Monitor(PrintStream printStream) {
			this.real = printStream;
			this.buffer = this.createByteBuffer ();
			String s = System.getProperty("line.separator");
			lineChar = s.charAt(s.length() -1);
		}

		PrintStream getReal() {
			return real;
		}

		@Override
		synchronized
		public void write(int b) throws IOException {
			buffer.add(Integer.valueOf(b).byteValue());

			if (b == lineChar) {
				String line = makeString();
				LogLine obj = createObject(line);
				Event event = new Event(Monitor.this, obj);
				try {
					publisher.publish(event);
				} catch (Throwable t) {
					onError(t, line);
				} finally {
					real.print(line);
				}
			}
		}

		protected String makeString() {
			byte[] bs = new byte[buffer.size()];
			for (int i=0; i<buffer.size(); i++) {
				bs[i] = buffer.get(i);
			}
			String str = new String(bs);
			buffer = this.createByteBuffer ();
			return str;
		}

		protected List<Byte> createByteBuffer () {
			return new ArrayList<Byte>(200);
		}

		protected abstract LogLine createObject(String str);

		protected void onError(Throwable t, String str) {

		}

	}

通过代码可以知道只需要代理java.io.OutputStream的write方法就可以了,并且可以将每次输出的一行字符串发送给外界。

如果要代理System.out可以这样写

System.setOut(new PrintStream(new Monitor(){
	...
}));


你可能感兴趣的:(拦截System.out和System.err)