本文目錄一覽:
- 1、使用JAVASSIST怎樣向Class文件中加入import語句?
- 2、struts2.2 jar包里為什麼沒有javassist.jar包
- 3、springmnv框架怎麼搭建
- 4、用Javassist修改方法的幾個問題
- 5、用JAVASSIST如何得到一個類中所有的內部類(inner class)?
- 6、javassist-3.11.0.GA.jar 起什麼作用
使用JAVASSIST怎樣向Class文件中加入import語句?
在ECLIPSE下打開我這個JAVASSIST工程的屬性對話框,選擇Java Build Path – Library,把將要用到的庫導入進去,JAVASSIST就能找到了
struts2.2 jar包里為什麼沒有javassist.jar包
這個包是 struts2.2.1開始才依賴的,可能開發組沒來得及加進下載包里吧!之前版本的struts是不需要這個包的,不知道你用不用maven,用的話只要寫依賴就行了,maven會自動去它的倉庫下載的,不過還是給倉庫的地址你好了,呵呵
需要哪個版本就選哪個吧
springmnv框架怎麼搭建
一、Spring MNV環境搭建:
1. jar包引入
Spring 2.5.6:spring.jar、spring-webmvc.jar、commons-logging.jar、cglib-nodep-2.1_3.jar
Hibernate 3.6.8:hibernate3.jar、hibernate-jpa-2.0-api-1.0.1.Final.jar、antlr-2.7.6.jar、commons-collections-3.1、dom4j-1.6.1.jar、javassist-3.12.0.GA.jar、jta-1.1.jar、slf4j-api-1.6.1.jar、slf4j-nop-1.6.4.jar、相應資料庫的驅動jar包
2. web.xml配置(部分)
!– Spring MVC配置 —
!– ====================================== —
servlet
servlet-namespring/servlet-name
servlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-class
!– 可以自定義servlet.xml配置文件的位置和名稱,默認為WEB-INF目錄下,名稱為[servlet-name]-servlet.xml,如spring-servlet.xml
init-param
param-namecontextConfigLocation/param-name
param-value/WEB-INF/spring-servlet.xml/param-value 默認
/init-param
—
load-on-startup1/load-on-startup
/servlet
servlet-mapping
servlet-namespring/servlet-name
url-pattern*.do/url-pattern
/servlet-mapping
!– Spring配置 —
!– ====================================== —
listener
listener-classorg.springframework.web.context.ContextLoaderListener/listener-class
/listener
!– 指定Spring Bean的配置文件所在目錄。默認配置在WEB-INF目錄下 —
context-param
param-namecontextConfigLocation/param-name
param-valueclasspath:config/applicationContext.xml/param-value
/context-param
3. spring-servlet.xml配置
spring-servlet這個名字是因為上面web.xml中servlet-name標籤配的值為spring(servlet-namespring/servlet-name),再加上「-servlet」後綴而形成的spring-servlet.xml文件名,如果改為springMVC,對應的文件名則為springMVC-servlet.xml。
?xml version=”1.0″ encoding=”UTF-8″?
beans xmlns=””
xmlns:xsi=”” xmlns:p=””
xmlns:context=””
xsi:schemaLocation=”
“
!– 啟用spring mvc 註解 —
context:annotation-config /
!– 設置使用註解的類所在的jar包 —
context:component-scan base-package=”controller”/context:component-scan
!– 完成請求和註解POJO的映射 —
bean class=”org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter” /
!– 對轉向頁面的路徑解析。prefix:前綴, suffix:後綴 —
bean class=”org.springframework.web.servlet.view.InternalResourceViewResolver” p:prefix=”/jsp/” p:suffix=”.jsp” /
/beans
4. applicationContext.xml配置
?xml version=”1.0″ encoding=”UTF-8″?
beans xmlns=””
xmlns:xsi=””
xmlns:aop=””
xmlns:tx=””
xsi:schemaLocation=”
“
!– 採用hibernate.cfg.xml方式配置數據源 —
bean id=”sessionFactory” class=”org.springframework.orm.hibernate3.LocalSessionFactoryBean”
property name=”configLocation”
valueclasspath:config/hibernate.cfg.xml/value
/property
/bean
!– 將事務與Hibernate關聯 —
bean id=”transactionManager” class=”org.springframework.orm.hibernate3.HibernateTransactionManager”
property name=”sessionFactory”
ref local=”sessionFactory”/
/property
/bean
!– 事務(註解 )–
tx:annotation-driven transaction-manager=”transactionManager” proxy-target-class=”true”/
!– 測試Service —
bean id=”loginService” class=”service.LoginService”/bean
!– 測試Dao —
bean id=”hibernateDao” class=”dao.HibernateDao”
property name=”sessionFactory” ref=”sessionFactory”/property
/bean
/beans
二、詳解
Spring MVC與Struts從原理上很相似(都是基於MVC架構),都有一個控制頁面請求的Servlet,處理完後跳轉頁面。看如下代碼(註解):
package controller;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import entity.User;
@Controller //類似Struts的Action
public class TestController {
@RequestMapping(“test/login.do”) // 請求url地址映射,類似Struts的action-mapping
public String testLogin(@RequestParam(value=”username”)String username, String password, HttpServletRequest request) {
// @RequestParam是指請求url地址映射中必須含有的參數(除非屬性required=false)
// @RequestParam可簡寫為:@RequestParam(“username”)
if (!”admin”.equals(username) || !”admin”.equals(password)) {
return “loginError”; // 跳轉頁面路徑(默認為轉發),該路徑不需要包含spring-servlet配置文件中配置的前綴和後綴
}
return “loginSuccess”;
}
@RequestMapping(“/test/login2.do”)
public ModelAndView testLogin2(String username, String password, int age){
// request和response不必非要出現在方法中,如果用不上的話可以去掉
// 參數的名稱是與頁面控制項的name相匹配,參數類型會自動被轉換
if (!”admin”.equals(username) || !”admin”.equals(password) || age 5) {
return new ModelAndView(“loginError”); // 手動實例化ModelAndView完成跳轉頁面(轉發),效果等同於上面的方法返回字元串
}
return new ModelAndView(new RedirectView(“../index.jsp”)); // 採用重定向方式跳轉頁面
// 重定向還有一種簡單寫法
// return new ModelAndView(“redirect:../index.jsp”);
}
@RequestMapping(“/test/login3.do”)
public ModelAndView testLogin3(User user) {
// 同樣支持參數為表單對象,類似於Struts的ActionForm,User不需要任何配置,直接寫即可
String username = user.getUsername();
String password = user.getPassword();
int age = user.getAge();
if (!”admin”.equals(username) || !”admin”.equals(password) || age 5) {
return new ModelAndView(“loginError”);
}
return new ModelAndView(“loginSuccess”);
}
@Resource(name = “loginService”) // 獲取applicationContext.xml中bean的id為loginService的,並注入
private LoginService loginService; //等價於spring傳統注入方式寫get和set方法,這樣的好處是簡潔工整,省去了不必要得代碼
@RequestMapping(“/test/login4.do”)
public String testLogin4(User user) {
if (loginService.login(user) == false) {
return “loginError”;
}
return “loginSuccess”;
}
}
以上4個方法示例,是一個Controller里含有不同的請求url,也可以採用一個url訪問,通過url參數來區分訪問不同的方法,代碼如下:
package controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping(“/test2/login.do”) // 指定唯一一個*.do請求關聯到該Controller
public class TestController2 {
@RequestMapping
public String testLogin(String username, String password, int age) {
// 如果不加任何參數,則在請求/test2/login.do時,便默認執行該方法
if (!”admin”.equals(username) || !”admin”.equals(password) || age 5) {
return “loginError”;
}
return “loginSuccess”;
}
@RequestMapping(params = “method=1”, method=RequestMethod.POST)
public String testLogin2(String username, String password) {
// 依據params的參數method的值來區分不同的調用方法
// 可以指定頁面請求方式的類型,默認為get請求
if (!”admin”.equals(username) || !”admin”.equals(password)) {
return “loginError”;
}
return “loginSuccess”;
}
@RequestMapping(params = “method=2”)
public String testLogin3(String username, String password, int age) {
if (!”admin”.equals(username) || !”admin”.equals(password) || age 5) {
return “loginError”;
}
return “loginSuccess”;
}
}
其實RequestMapping在Class上,可看做是父Request請求url,而RequestMapping在方法上的可看做是子Request請求url,父子請求url最終會拼起來與頁面請求url進行匹配,因此RequestMapping也可以這麼寫:
package controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping(“/test3/*”) // 父request請求url
public class TestController3 {
@RequestMapping(“login.do”) // 子request請求url,拼接後等價於/test3/login.do
public String testLogin(String username, String password, int age) {
if (!”admin”.equals(username) || !”admin”.equals(password) || age 5) {
return “loginError”;
}
return “loginSuccess”;
}
}
用Javassist修改方法的幾個問題
以通過一種手段來在程序內部來修改授權部分的實現,使真實的授權部分隱藏在其它代碼部分,而可視的授權代碼並不參與實際的授權授權,這樣的話,對於破解者來說,修改表向的代碼實現並不能真正修改代碼實現,因為真實的實現已經通過其它代碼將原始實現替換掉了。
即在調用授權代碼之前將授權原代碼進行修改,然後調用授權代碼時即調用已經修改後的授權代碼,而真實的授權代碼是查看不了的(通過某種方式注入),這樣即達到一種授權方式的隱藏。
可以通過javassist來修改java類的一個方法,來修改一個方法的真實實現。修改的方法可以是動態方法,也可以是靜態方法。修改的前提即是當前修改的類還沒有被當前jvm載入,如果當前的類已經被載入,則不能修改。
ClassPool classPool = ClassPool.getDefault();
CtClass ctClass = classPool.get(“com.develop.Txt”);
CtMethod ctMethod = ctClass.getDeclaredMethod(“i”);
ctMethod.setBody(“{try{Integer i = null;”
+ “int y = i.intValue();System.out.println(\”this is a new method\”);”);
ctClass.toClass();
上面的方法即是修改一個方法的實現,當調用ctClass.toClass()時,當前類即會被當前的classLoader載入,並實例化類。
需要注意的是,在調用ctClass.toClass()時,會載入此類,如果此類在之前已經被載入過,則會報一個duplicate load的錯誤,表示不能重複載入一個類。所以,修改方法的實現必須在修改的類載入之前進行。
即使不調用toClass,那麼如果當前修改的類已經載入,那麼修改方法實現,同樣不起作用,即修改一個已經載入的類(不論是修改靜態方法,還是修改動態方法)是沒有任何效果的。修改之前必須在類載入之前進行。
當然,使用aspectj也可以同樣達到修改的效果,不過修改指定的類,則需要為修改這個類添加一個aspect,然後將這個aspect加入配置文件中以使其生效,比起javassist來說,修改一個類還是使用javassist相對簡單一點。
用JAVASSIST如何得到一個類中所有的內部類(inner class)?
內部類:內部類也就是定義在類內部的類。
內部類的分類:成員內部類、局部內部類、 靜態內部類、匿名內部類
成員內部類
四個訪問許可權修飾符都可以修飾成員內部類。
內部類和外部類在編譯時時不同的兩個類,內部類對外部類沒有任何依賴。
內部類是一種編譯時語法,在編譯時生成的各自的位元組碼文件,內部類和外部類沒有關係。
內部類中可以訪問外部類的私有成員。
作為外部類的一個成員存在,與外部類的屬性、方法並列。
內部類和外部類的實例變數可以共存。
在內部類中訪問實例變數:this.屬性
在內部類訪問外部類的實例變數:外部類名.this.屬性。
在外部類的外部訪問內部類,使用out.inner.
成員內部類的特點:
1.內部類作為外部類的成員,可以訪問外部類的私有成員或屬性。(即使將外部類聲明為private,但是對於處於其內部的內部類還是可見的。)
2.用內部類定義在外部類中不可訪問的屬性。這樣就在外部類中實現了比外部類的private還要小的訪問許可權。
注意:內部類是一個編譯時的概念,一旦編譯成功,就會成為完全不同的兩類。
對於一個名為outer的外部類和其內部定義的名為inner的內部類。編譯完成後出現outer.class和outer$inner.class兩類。
3.成員內部類不能含有靜態成員。
建立內部類對象時應注意:
在外部類的內部可以直接使用inner s=new inner();(因為外部類知道inner是哪個類,所以可以生成對象。)
而在外部類的外部,要生成(new)一個內部類對象,需要首先建立一個外部類對象(外部類可用),然後在生成一個內部類對象。內部類的類名是外部類類名.內部類類名。
Outer o=new Outer();
Outer.Inner in=o.new.Inner()。
靜態內部類
(注意:前三種內部類與變數類似,所以可以對照參考變數)
靜態內部類定義在類中,任何方法外,用static class定義。
靜態內部類只能訪問外部類的靜態成員。
生成(new)一個靜態內部類不需要外部類成員:這是靜態內部類和成員內部類的區別。
靜態內部類的對象可以直接生成:
Outer.Inner in=new Outer.Inner();
而不需要通過生成外部類對象來生成。這樣實際上使靜態內部類成為了一個頂級類。靜態內部類不可用private來進行定義。
注意:當類與介面(或者是介面與介面)發生方法命名衝突的時候,此時必須使用內部類來實現。
用介面不能完全地實現多繼承,用介面配合內部類才能實現真正的多繼承。
例子:
對於兩個類,擁有相同的方法:
class People
{
run();
}
interface Machine{
run();
}
此時有一個robot類:
class Robot extends People implement Machine.
此時run()不可直接實現。
interface Machine
{
void run();
}
class Person
{
void run(){System.out.println(“run”);}
}
class Robot extends Person
{
private class MachineHeart implements Machine
{
public void run(){System.out.println(“heart run”);}
}
public void run(){System.out.println(“Robot run”);}
Machine getMachine(){return new MachineHeart();}
}
class Test
{
public static void main(String[] args)
{
Robot robot=new Robot();
Machine m=robot.getMachine();
m.run();
robot.run();
}
}
局部內部類
在方法中定義的內部類稱為局部內部類。
與局部變數類似,在局部內部類前不加修飾符public和private,其範圍為定義它的代碼塊。
注意:局部內部類不僅可以訪問外部類私有實例變數,但可以訪問外部類的局部常量(也就是局部變數必須為final的)
在類外不可直接訪問局部內部類(保證局部內部類對外是不可見的)。
在方法中才能調用其局部內部類。
通過內部類和介面達到一個強制的弱耦合,用局部內部類來實現介面,並在方法中返回介面類型,使局部內部類不可見,屏蔽實現類的可見性。
局部內部類寫法
public class TestLocalInnerClass{
public static void main(String[] args){
Outer o=new Outer();
final int a=9;
o.print(a);
}
}
class Outer{
private int index=100;
public void print(final int a){
final int b=10;
System.out.println(a);
class Inner{
public void print(){
System.out.println(index);
System.out.println(a);
System.out.println(b);
}
}
Inner i=new Inner();
i.print();
}
}
匿名內部類
匿名內部類是一種特殊的局部內部類,它是通過匿名類實現介面。
匿名內部類的特點:
1,一個類用於繼承其他類或是實現介面,並不需要增加額外的方法,只是對繼承方法的事先或是覆蓋。
2,只是為了獲得一個對象實例,不許要知道其實際類型。
3,類名沒有意義,也就是不需要使用到。
註:一個匿名內部類一定是在new的後面,用其隱含實現一個介面或實現一個類,沒有類名,根據多態,我們使用其父類名。
因其為局部內部類,那麼局部內部類的所有限制都對其生效。
匿名內部類是唯一一種無構造方法類。
大部分匿名內部類是用於介面回調用的。
匿名內部類在編譯的時候由系統自動起名Out$1.class。
如果一個對象編譯時的類型是介面,那麼其運行的類型為實現這個介面的類。
因匿名內部類無構造方法,所以其使用範圍非常的有限。
當需要多個對象時使用局部內部類,因此局部內部類的應用相對比較多。匿名內部類中不能定義構造方法。
匿名內部類的寫法:
interface A{
void ia();
}
class B{
public A bc(){
return new A{
void ia(){
}
};
}
}
使用匿名內部類:
B b=new B();
A a=b.bc();
a.ia();
javassist-3.11.0.GA.jar 起什麼作用
Javassist的(JAVA編程助手)使Java位元組碼操縱簡單。這是一個編輯Java位元組碼的類庫。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/243440.html