十三、java 实现 调用 打印机 代码详解
接口 PrintService 是 DocPrintJob 的工厂。PrintService 描述了打印机的功能,并可查询它来了解打印机支持的属性。
import java.io.File;
import java.io.FileInputStream;
import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.ServiceUI;
import javax.print.SimpleDoc;
import javax.print.attribute.DocAttributeSet;
import javax.print.attribute.HashDocAttributeSet;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.swing.JFileChooser;
/**
* 建立与打印机的连接
* @author Administrator
*
*/
public class PrintDemo {
public static void main(String[] args) {
JFileChooser fileChooser = new JFileChooser(); //创建打印作业
int state = fileChooser.showOpenDialog(null);
if(state == fileChooser.APPROVE_OPTION){
File file = new File("D:/zkyzl.txt"); //获取选择的文件
//构建打印请求属性集
HashPrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
//设置打印格式,因为未确定类型,所以选择autosense
DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
//查找所有的可用的打印服务
PrintService printService[] = PrintServiceLookup.lookupPrintServices(flavor, pras);
//定位默认的打印服务
PrintService defaultService = PrintServiceLookup.lookupDefaultPrintService();
//显示打印对话框
PrintService service = ServiceUI.printDialog(null, 200, 200, printService,
defaultService, flavor, pras);
if(service != null){
try {
DocPrintJob job = service.createPrintJob(); //创建打印作业
FileInputStream fis = new FileInputStream(file); //构造待打印的文件流
DocAttributeSet das = new HashDocAttributeSet();
Doc doc = new SimpleDoc(fis, flavor, das);
job.print(doc, pras);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
接口 PrintService 是 DocPrintJob 的工厂。PrintService 描述了打印机的功能,并可查询它来了解打印机支持的属性。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintException;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.ServiceUI;
import javax.print.SimpleDoc;
import javax.print.attribute.DocAttributeSet;
import javax.print.attribute.HashDocAttributeSet;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
/**
* 调用打印机功能
* @author Administrator
*
*/
public class PrintDemoII {
public static void main(String[] args) {
DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
PrintService []pservices = PrintServiceLookup.lookupPrintServices(flavor, aset);
PrintService defaultService = PrintServiceLookup.lookupDefaultPrintService();
PrintService service = ServiceUI.printDialog(null, 200, 200, pservices,
defaultService, flavor, aset);
if(service != null){
try {
DocPrintJob pj =service.createPrintJob();
FileInputStream fis = new FileInputStream("D:" + File.separator + "zkyzl.txt");
DocAttributeSet das = new HashDocAttributeSet();
Doc doc = new SimpleDoc(fis, flavor, das);
pj.print(doc, aset);
} catch (FileNotFoundException fe) {
fe.printStackTrace();
} catch (PrintException e) {
e.printStackTrace();
}
}else {
System.out.println("打印失败");
}
}
}
十四、JUnit 测试全部 case (TestSuite)
如果你不想要讓 TestRunner 找出預設的 testXXX()方法來執行測試,則可以使用TestSuite 來組合你想要執行的測試。例如:
import junit.framework.TestCase;
import junit.framework.TestSuite;
public class CalculatorTest extends TestCase {
private Calculator calculator;
public CalculatorTest() {}
public CalculatorTest(String name) {
super(name);
}
@Override
protected void setUp() {
calculator = new Calculator();
}
@Override
protected void tearDown() {
calculator = null;
}
public void testPlus() {
int expected = 5;
int result = calculator.plus(3, 2);
assertEquals(expected, result);
}
public void testMinus() {
int expected = 1;
int result = calculator.minus(3, 2);
assertEquals(expected, result);
}
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTest(new CalculatorTest("testPlus"));
return suite;
}
// IDE 中通常不需要這個main()
public static void main(String[] args) {
TestRunner.run(suite());
}
}
你可以定義一個靜態(static) 的suite()方法,使之傳回 TestSuite實例,在方法中組織你想要的測試方法,如果在IDE中,會自動發現這個 suite()方法、取得TestSuite、呼叫run()方法執行測試。事實上,你使用 TestRunner 的 run() 方法若傳入Class實例,也會自動幫你建立 TestSuite:
static public void run(Class testClass) {
run(new TestSuite(testClass));
}
TestSuite也實作了Test介面,這是為了以 Composite 模式 實現測試的任意組合:
正如先前的範例,此時在TestSuite的建構式中,會以反射找出所有testXXX()方法、建立TestCase實例並加入TestSuite中。
所以基本上,真正用來組合單元測試是TestSuite。TestSuite的addTest()接受的是Test介面的實作物件,所以TestCase與TestSuite都可以加入某個TestSuite中,另一個addTestSuite()方法名稱有點令人困惑,它並非接受TestSuite的實例,而是接受Class的實例,而它只不過是個代為建立TestSuite的簡便方法:
public void addTestSuite(Class testClass) {
addTest(new TestSuite(testClass));
}
例如,如果你已經有 OOOTest 、XXXTest 、YYYTest 等 TestCase 的子類別,如果想要寫個檔案,一次運行這三個測試案例,方式很簡單:
(全 case 测试,main()不要也可以,直接用 JUnit 运行)
public class TestAll {
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTestSuite(OOOTest.class);
suite.addTestSuite(XXXTest.class);
suite.addTestSuite(YYYTest.class);
return suite;
}
public static void main(String[] args) {
TestRunner.run(suite());
}
}
如果想讓 IDE 自動發現定義的 suite()方法,則繼承 TestCase 是必要的,所以可以如下撰寫:
public class TestAll extends TestCase {
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTestSuite(OOOTest.class);
suite.addTestSuite(XXXTest.class);
suite.addTestSuite(YYYTest.class);
return suite;
}
}
由於實現了 Composite 模式,所以組合的方式很多元化,例如:
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTest(new XXXTest("testABC")); // 執行testABC()方法
suite.addTest(YYYTest.suite()); // suite() 傳回 TestSuite實例
suite.addTestSuite(OOOTest.class); // 自動找出所有testXXX()方法
return suite;
}
TestRunner 最後會呼叫 TestSuite 的 run() 方法執行所有的測試:
public void run(TestResult result) {
for (Enumeration e= tests(); e.hasMoreElements(); ) {
if (result.shouldStop() )
break;
Test test= (Test)e.nextElement();
runTest(test, result);
}
}
public void runTest(Test test, TestResult result) {
test.run(result);
}
十五、java 解析 XML ,dom4j 解析 XML
books.xml:
<?xml version="1.0" encoding="UTF-8"?> <books> <!--This is a test for dom4j, jakoes, 2007.7.19--> <book show="yes" url="lucene.net"> <title id="456">Lucene Studing</title> </book> <book show="yes" url="dom4j.com"> <title id="123">Dom4j Tutorials</title> </book> <book show="no" url="spring.org"> <title id="789">Spring in Action</title> </book> <owner>O'Reilly</owner> </books>
下面我们使用dom4j的xPath来解析:
segmentOfParseXML.java:
public void parseBooks(){
SAXReader reader = new SAXReader();
try {
Document doc = reader.read("books.xml");
Node root = doc.selectSingleNode("/books");
List list = root.selectNodes("book[@url='dom4j.com']");
for(Object o:list){
Element e = (Element) o;
String show=e.attributeValue("show");
System.out.println("show = " + show);
}
} catch (Exception e) {
e.printStackTrace();
}
}
1. Document doc = reader.read("books.xml");的意思是加载XML文档,此是可以用doc.asXML()来查看,它将打印整个xml文档。
2. Node root = doc.selectSingleNode("/books");是读取刚才加载的xml文档内的books节点下的所有内容,对于本例也是整个xml文档。
当然我们也可以加载/books下的某一个节点,如:book节点
Node root = doc.selectSingleNode("/books/book");
或:Node root = doc.selectSingleNode("/books/*");
注意:如果有多个book节点,它只会读取第一个
root.asXML()将打印:
<book show="yes" url="lucene.net">
<title id="456">Lucene Studing</title>
</book>
3. 既然加载了这么多,怎么精确的得到想要的节点呢,看下面:
List list = root.selectNodes("book[@url='dom4j.com']");
它的意思就是读取books节点下的book节点,且book的节点的url属性为dom4j.com
为什么使用list来接收呢,如果有两个book节点,且它们的url属性都为dom4j.com,此时就封闭到list里了。
如果想读取books下的所有book节点,可以这样:
List list = root.selectNodes("book");
如果想读取books节点下的book节点下的title节点,可以这样:
List list2 = root.selectNodes("book[@url='dom4j.com']/title[@id='123']");
注意:selectNodes()参数的格式:
节点名[@属性名='属性值'],如:book[@url='dom4j.com']
如果有多个节点,用“/”分开,如:book[@url='dom4j.com']/title[@id='123']
最近就是读取封闭在List里的内容了,可以用Node来读取,也可以用Element来转换。
attributeValue("属性")是读取该节点的属性值
getText()是读取节点的的内容。
十六、java 分页 总页数 计算
只使用于 java
int totalPageNum = (totalRecord + pageSize - 1) / pageSize;
十七、CGlib 简单介绍
CGlib概述:
cglib(Code Generation Library)是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。
cglib封装了asm,可以在运行期动态生成新的class。
cglib用于AOP,jdk中的proxy必须基于接口,cglib却没有这个限制。
CGlib应用:
以一个实例在简单介绍下cglib的应用。
我们模拟一个虚拟的场景,关于信息的管理。
1)原始需求是任何人可以操作信息的create,update,delete,query操作。
InfoManager.java--封装对信息的操作
public class InfoManager {
// 模拟查询操作
public void query() {
System.out.println("query");
}
// 模拟创建操作
public void create() {
System.out.println("create");
}
// 模拟更新操作
public void update() {
System.out.println("update");
}
// 模拟删除操作
public void delete() {
System.out.println("delete");
}
}
InfoManagerFactory.java--工厂类
public class InfoManagerFactory {
private static InfoManager manger = new InfoManager();
/**
* 创建原始的InfoManager
*
* @return
*/
public static InfoManager getInstance() {
return manger;
}
}
client.java--供客户端调用
public class Client {
public static void main(String[] args) {
Client c = new Client();
c.anyonecanManager();
}
/**
* 模拟:没有任何权限要求,任何人都可以操作
*/
public void anyonecanManager() {
System.out.println("any one can do manager");
InfoManager manager = InfoManagerFactory.getInstance();
doCRUD(manager);
separatorLine();
}
/**
* 对Info做增加/更新/删除/查询操作
*
* @param manager
*/
private void doCRUD(InfoManager manager) {
manager.create();
manager.update();
manager.delete();
manager.query();
}
/**
* 加一个分隔行,用于区分
*/
private void separatorLine() {
System.out.println("################################");
}
}
至此,没有涉及到cglib的内容,因为需求太简单了,但是接下来,需求发生了改变,要求:
2)只有一个叫“maurice”的用户登录,才允许对信息进行create,update,delete,query的操作。
怎么办?难道在每个方法前,都加上一个权限判断吗?这样重复逻辑太多了,于是乎想到了Proxy(代理模式),但是原先的InfoManager也没有实现接口,不能采用jdk的proxy。那么cglib在这边就要隆重登场。
一旦使用cgblig,只需要添加一个MethodInterceptor的类以及修改factory代码就可以实现这个需求。
AuthProxy.java--权限校验代理类
public class AuthProxy implements MethodInterceptor {
private String name; // 会员登录名
public AuthProxy(String name) {
this.name = name;
}
/**
* 权限校验,如果会员名为:maurice,则有权限做操作,否则提示没有权限
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
if (!"maurice".equals(this.name)) {
System.out.println("AuthProxy:you have no permits to do manager!");
return null;
}
return proxy.invokeSuper(obj, args);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
InfoManagerFactory.java--代码变动如下:
public class InfoManagerFactory {
/**
* 创建带有权限检验的InfoManager
*
* @param auth
* @return
*/
public static InfoManager getAuthInstance(AuthProxy auth) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(InfoManager.class);
enhancer.setCallback(auth);
return (InfoManager) enhancer.create();
}
}
client.java--代码修改如下
public class Client {
public static void main(String[] args) {
Client c = new Client();
c.haveNoAuthManager();
c.haveAuthManager();
}
/**
* 模拟:登录会员没有权限
*/
public void haveNoAuthManager() {
System.out.println("the loginer's name is not maurice,so have no permits do manager");
InfoManager noAuthManager = InfoManagerFactory.getAuthInstance(new AuthProxy("maurice1"));
doCRUD(noAuthManager);
separatorLine();
}
/**
* 模拟:登录会员有权限
*/
public void haveAuthManager() {
System.out.println("the loginer's name is maurice,so have permits do manager");
InfoManager authManager = InfoManagerFactory.getAuthInstance(new AuthProxy("maurice"));
doCRUD(authManager);
separatorLine();
}
/**
* 对Info做增加/更新/删除/查询操作
*
* @param manager
*/
private void doCRUD(InfoManager manager) {
manager.create();
manager.update();
manager.delete();
manager.query();
}
/**
* 加一个分隔行,用于区分
*/
private void separatorLine() {
System.out.println("################################");
}
}
执行下代码,发现这时client端中已经加上了权限校验。
同样是InfoManager,为什么这时能多了权限的判断呢?Factory中enhancer.create()返回的到底是什么对象呢?这个疑问将在第三部分CGlib中解释。
这边的代码,其实是介绍了cglib中的enhancer功能.
到这里,参照上面的代码,就可以使用cglib带来的aop功能了。但是为了更多介绍下cglib的功能,模拟需求再次发生变化:
3)由于query功能用户maurice才能使用,招来其他用户的强烈的抱怨,所以权限再次变更,只有create,update,delete,才需要权限保护,query任何人都可以使用。
怎么办?采用AuthProxy,使得InfoManager中的所有方法都被代理,加上了权限的判断。当然,最容易想到的办法,就是在 AuthProxy的intercept的方法中再做下判断,如果代理的method是query,不需要权限验证。这么做,可以,但是一旦逻辑比较复杂 的时候,intercept这个方法要做的事情会很多,逻辑会异常的复杂。
幸好,cglib还提供了CallbackFilter。使用CallbackFilter,可以明确表明,被代理的类(InfoManager)中不同的方法,被哪个拦截器(interceptor)拦截。
AuthProxyFilter.java
public class AuthProxyFilter implements CallbackFilter {
private static final int AUTH_NEED = 0;
private static final int AUTH_NOT_NEED = 1;
/**
* <pre>
* 选择使用的proxy
* 如果调用query函数,则使用第二个proxy
* 否则,使用第一个proxy
* </pre>
*/
@Override
public int accept(Method method) {
if ("query".equals(method.getName())) {
return AUTH_NOT_NEED;
}
return AUTH_NEED;
}
}
这段代码什么意思?其中的accept方法的意思是说,如果代理的方法是query(),那么使用第二个拦截器去拦截,如果代理的方法不是 query(),那么使用第一个拦截器去拦截。所以我们只要再写一个拦截器,不做权限校验就行了。(其实,cglib中的NoOp.INSTANCE就是 一个空的拦截器,只要配置上这个就可以了。)
InfoManagerFactory.java--代码修改如下:(配置不同的拦截器和filter)
public class InfoManagerFactory {
/**
* 创建不同权限要求的InfoManager
*
* @param auth
* @return
*/
public static InfoManager getSelectivityAuthInstance(AuthProxy auth) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(InfoManager.class);
enhancer.setCallbacks(new Callback[] { auth, NoOp.INSTANCE });
enhancer.setCallbackFilter(new AuthProxyFilter());
return (InfoManager) enhancer.create();
}
}
记住:setCallbacks中的拦截器(interceptor)的顺序,一定要和CallbackFilter里面指定的顺序一致!!切忌。
Client.java
public class Client {
public static void main(String[] args) {
Client c = new Client();
c.selectivityAuthManager();
}
/**
* 模拟:没有权限的会员,可以作查询操作
*/
public void selectivityAuthManager() {
System.out.println("the loginer's name is not maurice,so have no permits do manager except do query operator");
InfoManager authManager = InfoManagerFactory.getSelectivityAuthInstance(new AuthProxy("maurice1"));
doCRUD(authManager);
separatorLine();
}
/**
* 对Info做增加/更新/删除/查询操作
*
* @param manager
*/
private void doCRUD(InfoManager manager) {
manager.create();
manager.update();
manager.delete();
manager.query();
}
/**
* 加一个分隔行,用于区分
*/
private void separatorLine() {
System.out.println("################################");
}
}
此时,对于query的权限校验已经被去掉了。
通过一个模拟需求,简单介绍了cglib aop功能的使用。
CGlib应用非常广,在spring,hibernate等框架中,被大量的使用。
CGlib原理:
cglib神奇吗?其实一旦了解cglib enhancer的原理,一切就真相大白了。
刚才在第二部分中,有个疑问:enhancer.create()到底返回了什么对象?
其实在刚才的例子中,cglib在代码运行期,动态生成了InfoManager的子类,并且根据CallbackFilter的accept方法,覆写了InfoManager中的所有方法--去执行相应的MethodInterceptor的intercept方法。
有兴趣的朋友可以看看我反编译的InfoManager的子类,就可以很明白知道具体的实现了。(需要有耐心才可以)
InfoManager$$EnhancerByCGLIB$$de624598.jad
// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/kpdus/jad.html
// Decompiler options: packimports(3)
// Source File Name: <generated>
package cn.eulic.codelab.cglib;
import java.lang.reflect.Method;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.*;
// Referenced classes of package cn.eulic.codelab.cglib:
// InfoManager
public class CGLIB.BIND_CALLBACKS extends InfoManager
implements Factory
{
static void CGLIB$STATICHOOK1()
{
Class class1;
ClassLoader classloader;
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
classloader = (class1 = Class.forName("cn.eulic.codelab.cglib.InfoManager$$EnhancerByCGLIB$$de624598")).getClassLoader();
classloader;
CGLIB$emptyArgs = new Object[0];
CGLIB$delete$0$Proxy = MethodProxy.create(classloader, (CGLIB$delete$0$Method = Class.forName("cn.eulic.codelab.cglib.InfoManager").getDeclaredMethod("delete", new Class[0])).getDeclaringClass(), class1, "()V", "delete", "CGLIB$delete$0");
CGLIB$create$1$Proxy = MethodProxy.create(classloader, (CGLIB$create$1$Method = Class.forName("cn.eulic.codelab.cglib.InfoManager").getDeclaredMethod("create", new Class[0])).getDeclaringClass(), class1, "()V", "create", "CGLIB$create$1");
CGLIB$query$2$Proxy = MethodProxy.create(classloader, (CGLIB$query$2$Method = Class.forName("cn.eulic.codelab.cglib.InfoManager").getDeclaredMethod("query", new Class[0])).getDeclaringClass(), class1, "()V", "query", "CGLIB$query$2");
CGLIB$update$3$Proxy = MethodProxy.create(classloader, (CGLIB$update$3$Method = Class.forName("cn.eulic.codelab.cglib.InfoManager").getDeclaredMethod("update", new Class[0])).getDeclaringClass(), class1, "()V", "update", "CGLIB$update$3");
CGLIB$finalize$4$Proxy = MethodProxy.create(classloader, (CGLIB$finalize$4$Method = Class.forName("java.lang.Object").getDeclaredMethod("finalize", new Class[0])).getDeclaringClass(), class1, "()V", "finalize", "CGLIB$finalize$4");
CGLIB$hashCode$5$Proxy = MethodProxy.create(classloader, (CGLIB$hashCode$5$Method = Class.forName("java.lang.Object").getDeclaredMethod("hashCode", new Class[0])).getDeclaringClass(), class1, "()I", "hashCode", "CGLIB$hashCode$5");
CGLIB$clone$6$Proxy = MethodProxy.create(classloader, (CGLIB$clone$6$Method = Class.forName("java.lang.Object").getDeclaredMethod("clone", new Class[0])).getDeclaringClass(), class1, "()Ljava/lang/Object;", "clone", "CGLIB$clone$6");
CGLIB$equals$7$Proxy = MethodProxy.create(classloader, (CGLIB$equals$7$Method = Class.forName("java.lang.Object").getDeclaredMethod("equals", new Class[] {
Class.forName("java.lang.Object")
})).getDeclaringClass(), class1, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$7");
CGLIB$toString$8$Proxy = MethodProxy.create(classloader, (CGLIB$toString$8$Method = Class.forName("java.lang.Object").getDeclaredMethod("toString", new Class[0])).getDeclaringClass(), class1, "()Ljava/lang/String;", "toString", "CGLIB$toString$8");
return;
}
final void CGLIB$delete$0()
{
super.delete();
}
public final void delete()
{
CGLIB$CALLBACK_0;
if(CGLIB$CALLBACK_0 != null) goto _L2; else goto _L1
_L1:
JVM INSTR pop ;
CGLIB$BIND_CALLBACKS(this);
CGLIB$CALLBACK_0;
_L2:
JVM INSTR dup ;
JVM INSTR ifnull 37;
goto _L3 _L4
_L3:
break MISSING_BLOCK_LABEL_21;
_L4:
break MISSING_BLOCK_LABEL_37;
this;
CGLIB$delete$0$Method;
CGLIB$emptyArgs;
CGLIB$delete$0$Proxy;
intercept();
return;
super.delete();
return;
}
final void CGLIB$create$1()
{
super.create();
}
public final void create()
{
CGLIB$CALLBACK_0;
if(CGLIB$CALLBACK_0 != null) goto _L2; else goto _L1
_L1:
JVM INSTR pop ;
CGLIB$BIND_CALLBACKS(this);
CGLIB$CALLBACK_0;
_L2:
JVM INSTR dup ;
JVM INSTR ifnull 37;
goto _L3 _L4
_L3:
break MISSING_BLOCK_LABEL_21;
_L4:
break MISSING_BLOCK_LABEL_37;
this;
CGLIB$create$1$Method;
CGLIB$emptyArgs;
CGLIB$create$1$Proxy;
intercept();
return;
super.create();
return;
}
final void CGLIB$query$2()
{
super.query();
}
public final void query()
{
CGLIB$CALLBACK_0;
if(CGLIB$CALLBACK_0 != null) goto _L2; else goto _L1
_L1:
JVM INSTR pop ;
CGLIB$BIND_CALLBACKS(this);
CGLIB$CALLBACK_0;
_L2:
JVM INSTR dup ;
JVM INSTR ifnull 37;
goto _L3 _L4
_L3:
break MISSING_BLOCK_LABEL_21;
_L4:
break MISSING_BLOCK_LABEL_37;
this;
CGLIB$query$2$Method;
CGLIB$emptyArgs;
CGLIB$query$2$Proxy;
intercept();
return;
super.query();
return;
}
final void CGLIB$update$3()
{
super.update();
}
public final void update()
{
CGLIB$CALLBACK_0;
if(CGLIB$CALLBACK_0 != null) goto _L2; else goto _L1
_L1:
JVM INSTR pop ;
CGLIB$BIND_CALLBACKS(this);
CGLIB$CALLBACK_0;
_L2:
JVM INSTR dup ;
JVM INSTR ifnull 37;
goto _L3 _L4
_L3:
break MISSING_BLOCK_LABEL_21;
_L4:
break MISSING_BLOCK_LABEL_37;
this;
CGLIB$update$3$Method;
CGLIB$emptyArgs;
CGLIB$update$3$Proxy;
intercept();
return;
super.update();
return;
}
final void CGLIB$finalize$4()
throws Throwable
{
super.finalize();
}
protected final void finalize()
throws Throwable
{
CGLIB$CALLBACK_0;
if(CGLIB$CALLBACK_0 != null) goto _L2; else goto _L1
_L1:
JVM INSTR pop ;
CGLIB$BIND_CALLBACKS(this);
CGLIB$CALLBACK_0;
_L2:
JVM INSTR dup ;
JVM INSTR ifnull 37;
goto _L3 _L4
_L3:
break MISSING_BLOCK_LABEL_21;
_L4:
break MISSING_BLOCK_LABEL_37;
this;
CGLIB$finalize$4$Method;
CGLIB$emptyArgs;
CGLIB$finalize$4$Proxy;
intercept();
return;
super.finalize();
return;
}
final int CGLIB$hashCode$5()
{
return super.hashCode();
}
public final int hashCode()
{
CGLIB$CALLBACK_0;
if(CGLIB$CALLBACK_0 != null) goto _L2; else goto _L1
_L1:
JVM INSTR pop ;
CGLIB$BIND_CALLBACKS(this);
CGLIB$CALLBACK_0;
_L2:
JVM INSTR dup ;
JVM INSTR ifnull 52;
goto _L3 _L4
_L3:
this;
CGLIB$hashCode$5$Method;
CGLIB$emptyArgs;
CGLIB$hashCode$5$Proxy;
intercept();
JVM INSTR dup ;
JVM INSTR ifnonnull 45;
goto _L5 _L6
_L5:
JVM INSTR pop ;
0;
goto _L7
_L6:
(Number);
intValue();
_L7:
return;
_L4:
return super.hashCode();
}
final Object CGLIB$clone$6()
throws CloneNotSupportedException
{
return super.clone();
}
protected final Object clone()
throws CloneNotSupportedException
{
CGLIB$CALLBACK_0;
if(CGLIB$CALLBACK_0 != null) goto _L2; else goto _L1
_L1:
JVM INSTR pop ;
CGLIB$BIND_CALLBACKS(this);
CGLIB$CALLBACK_0;
_L2:
JVM INSTR dup ;
JVM INSTR ifnull 37;
goto _L3 _L4
_L3:
this;
CGLIB$clone$6$Method;
CGLIB$emptyArgs;
CGLIB$clone$6$Proxy;
intercept();
return;
_L4:
return super.clone();
}
final boolean CGLIB$equals$7(Object obj)
{
return super.equals(obj);
}
public final boolean equals(Object obj)
{
CGLIB$CALLBACK_0;
if(CGLIB$CALLBACK_0 != null) goto _L2; else goto _L1
_L1:
JVM INSTR pop ;
CGLIB$BIND_CALLBACKS(this);
CGLIB$CALLBACK_0;
_L2:
JVM INSTR dup ;
JVM INSTR ifnull 57;
goto _L3 _L4
_L3:
this;
CGLIB$equals$7$Method;
new Object[] {
obj
};
CGLIB$equals$7$Proxy;
intercept();
JVM INSTR dup ;
JVM INSTR ifnonnull 50;
goto _L5 _L6
_L5:
JVM INSTR pop ;
false;
goto _L7
_L6:
(Boolean);
booleanValue();
_L7:
return;
_L4:
return super.equals(obj);
}
final String CGLIB$toString$8()
{
return super.toString();
}
public final String toString()
{
CGLIB$CALLBACK_0;
if(CGLIB$CALLBACK_0 != null) goto _L2; else goto _L1
_L1:
JVM INSTR pop ;
CGLIB$BIND_CALLBACKS(this);
CGLIB$CALLBACK_0;
_L2:
JVM INSTR dup ;
JVM INSTR ifnull 40;
goto _L3 _L4
_L3:
this;
CGLIB$toString$8$Method;
CGLIB$emptyArgs;
CGLIB$toString$8$Proxy;
intercept();
(String);
return;
_L4:
return super.toString();
}
public static MethodProxy CGLIB$findMethodProxy(Signature signature)
{
String s = signature.toString();
s;
s.hashCode();
JVM INSTR lookupswitch 9: default 200
// -1949253108: 92
// -1574182249: 104
// -1166709331: 116
// -508378822: 128
// -358764054: 140
// 598313209: 152
// 1826985398: 164
// 1913648695: 176
// 1984935277: 188;
goto _L1 _L2 _L3 _L4 _L5 _L6 _L7 _L8 _L9 _L10
_L2:
"update()V";
equals();
JVM INSTR ifeq 201;
goto _L11 _L12
_L12:
break MISSING_BLOCK_LABEL_201;
_L11:
return CGLIB$update$3$Proxy;
_L3:
"finalize()V";
equals();
JVM INSTR ifeq 201;
goto _L13 _L14
_L14:
break MISSING_BLOCK_LABEL_201;
_L13:
return CGLIB$finalize$4$Proxy;
_L4:
"query()V";
equals();
JVM INSTR ifeq 201;
goto _L15 _L16
_L16:
break MISSING_BLOCK_LABEL_201;
_L15:
return CGLIB$query$2$Proxy;
_L5:
"clone()Ljava/lang/Object;";
equals();
JVM INSTR ifeq 201;
goto _L17 _L18
_L18:
break MISSING_BLOCK_LABEL_201;
_L17:
return CGLIB$clone$6$Proxy;
_L6:
"delete()V";
equals();
JVM INSTR ifeq 201;
goto _L19 _L20
_L20:
break MISSING_BLOCK_LABEL_201;
_L19:
return CGLIB$delete$0$Proxy;
_L7:
"create()V";
equals();
JVM INSTR ifeq 201;
goto _L21 _L22
_L22:
break MISSING_BLOCK_LABEL_201;
_L21:
return CGLIB$create$1$Proxy;
_L8:
"equals(Ljava/lang/Object;)Z";
equals();
JVM INSTR ifeq 201;
goto _L23 _L24
_L24:
break MISSING_BLOCK_LABEL_201;
_L23:
return CGLIB$equals$7$Proxy;
_L9:
"toString()Ljava/lang/String;";
equals();
JVM INSTR ifeq 201;
goto _L25 _L26
_L26:
break MISSING_BLOCK_LABEL_201;
_L25:
return CGLIB$toString$8$Proxy;
_L10:
"hashCode()I";
equals();
JVM INSTR ifeq 201;
goto _L27 _L28
_L28:
break MISSING_BLOCK_LABEL_201;
_L27:
return CGLIB$hashCode$5$Proxy;
_L1:
JVM INSTR pop ;
return null;
}
public static void CGLIB$SET_THREAD_CALLBACKS(Callback acallback[])
{
CGLIB$THREAD_CALLBACKS.set(acallback);
}
public static void CGLIB$SET_STATIC_CALLBACKS(Callback acallback[])
{
CGLIB$STATIC_CALLBACKS = acallback;
}
private static final void CGLIB$BIND_CALLBACKS(Object obj)
{
CGLIB.STATIC_CALLBACKS static_callbacks = (CGLIB.STATIC_CALLBACKS)obj;
if(static_callbacks.CGLIB$BOUND) goto _L2; else goto _L1
_L1:
Object obj1;
static_callbacks.CGLIB$BOUND = true;
obj1 = CGLIB$THREAD_CALLBACKS.get();
obj1;
if(obj1 != null) goto _L4; else goto _L3
_L3:
JVM INSTR pop ;
CGLIB$STATIC_CALLBACKS;
if(CGLIB$STATIC_CALLBACKS != null) goto _L4; else goto _L5
_L5:
JVM INSTR pop ;
goto _L2
_L4:
(Callback[]);
static_callbacks;
JVM INSTR swap ;
0;
JVM INSTR aaload ;
(MethodInterceptor);
CGLIB$CALLBACK_0;
_L2:
}
public Object newInstance(Callback acallback[])
{
CGLIB$SET_THREAD_CALLBACKS(acallback);
CGLIB$SET_THREAD_CALLBACKS(null);
return new <init>();
}
public Object newInstance(Callback callback)
{
CGLIB$SET_THREAD_CALLBACKS(new Callback[] {
callback
});
CGLIB$SET_THREAD_CALLBACKS(null);
return new <init>();
}
public Object newInstance(Class aclass[], Object aobj[], Callback acallback[])
{
CGLIB$SET_THREAD_CALLBACKS(acallback);
JVM INSTR new #2 <Class InfoManager$$EnhancerByCGLIB$$de624598>;
JVM INSTR dup ;
aclass;
aclass.length;
JVM INSTR tableswitch 0 0: default 35
// 0 28;
goto _L1 _L2
_L2:
JVM INSTR pop ;
<init>();
goto _L3
_L1:
JVM INSTR pop ;
throw new IllegalArgumentException("Constructor not found");
_L3:
CGLIB$SET_THREAD_CALLBACKS(null);
return;
}
public Callback getCallback(int i)
{
CGLIB$BIND_CALLBACKS(this);
this;
i;
JVM INSTR tableswitch 0 0: default 30
// 0 24;
goto _L1 _L2
_L2:
CGLIB$CALLBACK_0;
goto _L3
_L1:
JVM INSTR pop ;
null;
_L3:
return;
}
public void setCallback(int i, Callback callback)
{
this;
callback;
i;
JVM INSTR tableswitch 0 0: default 29
// 0 20;
goto _L1 _L2
_L2:
(MethodInterceptor);
CGLIB$CALLBACK_0;
goto _L3
_L1:
JVM INSTR pop2 ;
_L3:
}
public Callback[] getCallbacks()
{
CGLIB$BIND_CALLBACKS(this);
this;
return (new Callback[] {
CGLIB$CALLBACK_0
});
}
public void setCallbacks(Callback acallback[])
{
this;
acallback;
JVM INSTR dup2 ;
0;
JVM INSTR aaload ;
(MethodInterceptor);
CGLIB$CALLBACK_0;
}
private boolean CGLIB$BOUND;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback CGLIB$STATIC_CALLBACKS[];
private MethodInterceptor CGLIB$CALLBACK_0;
private static final Method CGLIB$delete$0$Method;
private static final MethodProxy CGLIB$delete$0$Proxy;
private static final Object CGLIB$emptyArgs[];
private static final Method CGLIB$create$1$Method;
private static final MethodProxy CGLIB$create$1$Proxy;
private static final Method CGLIB$query$2$Method;
private static final MethodProxy CGLIB$query$2$Proxy;
private static final Method CGLIB$update$3$Method;
private static final MethodProxy CGLIB$update$3$Proxy;
private static final Method CGLIB$finalize$4$Method;
private static final MethodProxy CGLIB$finalize$4$Proxy;
private static final Method CGLIB$hashCode$5$Method;
private static final MethodProxy CGLIB$hashCode$5$Proxy;
private static final Method CGLIB$clone$6$Method;
private static final MethodProxy CGLIB$clone$6$Proxy;
private static final Method CGLIB$equals$7$Method;
private static final MethodProxy CGLIB$equals$7$Proxy;
private static final Method CGLIB$toString$8$Method;
private static final MethodProxy CGLIB$toString$8$Proxy;
static
{
CGLIB$STATICHOOK1();
}
public ()
{
CGLIB$BIND_CALLBACKS(this);
}
}
附件如下:
cglib sample
十八、java动态代理(JDK和cglib)
JAVA的动态代理
代理模式
代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托 类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代 理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
按照代理的创建时期,代理类可以分为两种。
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。
首先看一下静态代理:
1、Count.java
/**
* 定义一个账户接口
*
* @author Administrator
*
*/
public interface Count {
// 查看账户方法
public void queryCount();
// 修改账户方法
public void updateCount();
}
2、CountImpl.java
package net.battier.dao.impl;
import net.battier.dao.Count;
/**
* 委托类(包含业务逻辑)
*
* @author Administrator
*
*/
public class CountImpl implements Count {
@Override
public void queryCount() {
System.out.println("查看账户方法...");
}
@Override
public void updateCount() {
System.out.println("修改账户方法...");
}
}
、CountProxy.java
package net.battier.dao.impl;
import net.battier.dao.Count;
/**
* 这是一个代理类(增强CountImpl实现类)
*
* @author Administrator
*
*/
public class CountProxy implements Count {
private CountImpl countImpl;
/**
* 覆盖默认构造器
*
* @param countImpl
*/
public CountProxy(CountImpl countImpl) {
this.countImpl = countImpl;
}
@Override
public void queryCount() {
System.out.println("事务处理之前");
// 调用委托类的方法;
countImpl.queryCount();
System.out.println("事务处理之后");
}
@Override
public void updateCount() {
System.out.println("事务处理之前");
// 调用委托类的方法;
countImpl.updateCount();
System.out.println("事务处理之后");
}
}
3、TestCount.java
package net.battier.test;
import net.battier.dao.impl.CountImpl;
import net.battier.dao.impl.CountProxy;
/**
*测试Count类
*
* @author Administrator
*
*/
public class TestCount {
public static void main(String[] args) {
CountImpl countImpl = new CountImpl();
CountProxy countProxy = new CountProxy(countImpl);
countProxy.updateCount();
countProxy.queryCount();
}
}
观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他 的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。
再来看一下动态代理:
JDK动态代理中包含一个类和一个接口:
InvocationHandler接口:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
参数说明:
Object proxy:指被代理的对象。
Method method:要调用的方法
Object[] args:方法调用时所需要的参数
可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject。
Proxy类:
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
参数说明:
ClassLoader loader:类加载器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子类实例
Ps:类加载器
在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有一下三种类加载器;
Booststrap ClassLoader:此加载器采用C++编写,一般开发中是看不到的;
Extendsion ClassLoader:用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类;
AppClassLoader:(默认)加载classpath指定的类,是最常使用的是一种加载器。
动态代理
与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。 动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。
动态代理示例:
1、BookFacade.java
package net.battier.dao;
public interface BookFacade {
public void addBook();
}
2、BookFacadeImpl.java
package net.battier.dao.impl;
import net.battier.dao.BookFacade;
public class BookFacadeImpl implements BookFacade {
@Override
public void addBook() {
System.out.println("增加图书方法。。。");
}
}
、BookFacadeProxy.java
package net.battier.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK动态代理代理类
*
* @author student
*
*/
public class BookFacadeProxy implements InvocationHandler {
private Object target;
/**
* 绑定委托对象并返回一个代理类
* @param target
* @return
*/
public Object bind(Object target) {
this.target = target;
//取得代理对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this); //要绑定接口(这是一个缺陷,cglib弥补了这一缺陷)
}
@Override
/**
* 调用方法
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result=null;
System.out.println("事物开始");
//执行方法
result=method.invoke(target, args);
System.out.println("事物结束");
return result;
}
}
3、TestProxy.java
package net.battier.test;
import net.battier.dao.BookFacade;
import net.battier.dao.impl.BookFacadeImpl;
import net.battier.proxy.BookFacadeProxy;
public class TestProxy {
public static void main(String[] args) {
BookFacadeProxy proxy = new BookFacadeProxy();
BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());
bookProxy.addBook();
}
}
但是,JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。
Cglib动态代理
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
示例
1、BookFacadeCglib.java
package net.battier.dao;
public interface BookFacade {
public void addBook();
}
2、BookCadeImpl1.java
package net.battier.dao.impl;
/**
* 这个是没有实现接口的实现类
*
* @author student
*
*/
public class BookFacadeImpl1 {
public void addBook() {
System.out.println("增加图书的普通方法...");
}
}
3、BookFacadeProxy.java
package net.battier.proxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 使用cglib动态代理
*
* @author student
*
*/
public class BookFacadeCglib implements MethodInterceptor {
private Object target;
/**
* 创建代理对象
*
* @param target
* @return
*/
public Object getInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
// 回调方法
enhancer.setCallback(this);
// 创建代理对象
return enhancer.create();
}
@Override
// 回调方法
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("事物开始");
proxy.invokeSuper(obj, args);
System.out.println("事物结束");
return null;
}
}
4、TestCglib.java
package net.battier.test;
import net.battier.dao.impl.BookFacadeImpl1;
import net.battier.proxy.BookFacadeCglib;
public class TestCglib {
public static void main(String[] args) {
BookFacadeCglib cglib=new BookFacadeCglib();
BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());
bookCglib.addBook();
}
}