首页 > 编程知识 正文

javassist库小实例的简单介绍

时间:2023-12-27 22:28:03 阅读:327201 作者:KAPW

本文目录一览:

使用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字节码的类库。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。