SSH框架教程完整版(附Github源码)

  • SSH框架的合成及GiuHub源码详见另一篇博客:搭建SSH框架

1. Struts2学习:

1-1. 搭建Struts2框架:
   1)新建Web项目,导入Struts2运行的类库(Struts2.5以后xwork-core.jar集成到struts-core.jar中,不用导入)-->Build Configuration Path关联类库。
   2)在web.xml中配置核心过滤器:

    ......
    
	
	
		struts2
		org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter
	
	
		struts2
		/*
	

3)创建控制器struts.xml(里面的内容不能缺失,否则报错):




	
		
			/day01/register_success.jsp
			/day01/register_error.jsp
		
	

4)构造 jsp页面、action类。
5)出现的问题解决方案:

  • java.lang.NoClassDefFoundError: Lorg/apache/logging/log4j/Logger解决办法:https://blog.csdn.net/Ricardo_MLi/article/details/72748256
  • There is no Action mapped for namespace / and action name解决办法:https://blog.csdn.net/dhaoxiansheng/article/details/54585243
1-2. Struts数据交互

1)JSP将数据传递给Action类的两种方式:

  • 直接传递对应的属性给Action类(属性名必须一一对应);
  • jsp传递给Action的实体类,Action再从实体类中取出相应的数据进行操作,从而实现底层业务与逻辑处理的分离开发。
//在jsp提交页面的定义:



//Manager是一个实体类,包含jsp页面传过来的属性的定义
//在Action类中,主要代码逻辑如下:
private Manager manager;
public void setManager(Manager manager){
	this.manager = manager;
}
public Manager getManager(){
	return this.manager;
}
System.out.println(this.manager.getUsername() + " " +  this.manager.getPassword() );

2)Action将数据传递给JSP页面

  • 通过在Action处理调用Service层,Service层再调用DAO层获取数据
  • 将Action类获取的数据封装成List转发给JSP页面;
  • JSP页面通过JSTL和EL表达式将获取的封装的数据进行显示。

3)Action调用servlet的API保存信息

  • 例:保存用户信息:
//1.在Action的execute()方法里面保存jsp页面的信息供后续使用
//1-1 通过上下文获取信息
Map session = ActionContext.getContext().getSession();
session.put("username", username);

//1-2 或者通过request(response、cookie的获取方式相同)保存信息,作用范围不同的区别
//获取request对象的MAP
Map request = (Map) ActionContext.getContext().get("request");
//将用户名保存到request对象的MAP中
request.put("username", username);

//2. 在jsp页面中通过EL表达式调用session / ... 中的信息
${sessionScope.username} / ${username}
  • 类似于通过Servlet调用API保存信息再转发:
@WebServlet("/login.action") //相当于struts.xml定义的action
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
.....

//创建session域对象,把user信息存储到session里面
request.getSession().setAttribute("session_user", user);
					
//携带用户名的值跳转到首页
request.getRequestDispatcher("index.action").forward(request, response);

.....
}
  • 另一种方式是通过ServletActionContext同样获取,但其耦合性比较高,不推荐使用。
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session =  ServletActionContext.getRequest().getSession();
1.3 Struts2.xml文件的配置

1)配置说明:

/day01/register_success.jsp
/day01/register_error.jsp
  • name 对应的是从Action返回的信息字符串;
  • < result >value< /result >的value指向请求转发的路径;
  • type默认情况下是dispatcher,类似于Servlet中的请求转发:request.getRequestDispatcher("/xxx.jsp / xxx.action").forward(request,response),数据可以通过request转发,但是它们的路径没有发生改变;
  • 当type = " redirect"时,表示该请求方式是重定向,数据不会通过request转发,路径发生了改变。

关于请求转发与重定向:https://blog.csdn.net/meiyalei/article/details/2129120

2)配置文件学习说明 1 :
规范化包的存放,其中namespace指定访问的路径,可不指定该属性,访问时路径名应指定namespace:…/admin/userlist.action
SSH框架教程完整版(附Github源码)_第1张图片

3)配置文件学习说明 2 之动态方法调用:
动态调用Action里面的方法,实现代码重用,逻辑分离

  • 在Action类里面添加实现的方法,返回值为String类型
    SSH框架教程完整版(附Github源码)_第2张图片

  • 在struts.xml配置文件中修改默认的动态调用值为 true,定义action的name(不能一样),class,method以及返回的处理结果result的跳转页面。
    SSH框架教程完整版(附Github源码)_第3张图片

  • 访问路径:·····/namespace/actionName ! methodName.action
    method访问地址

4) struts通配符的使用:struts通配符的使用应该提前约定好,避免出现用法的差异造成代码混乱,struts通配符的使用能减少action的定义,减少struts.xml中代码的冗余。

  • 配置通配符

SSH框架教程完整版(附Github源码)_第4张图片

  • 前端访问实例:

SSH框架教程完整版(附Github源码)_第5张图片

  • 访问地址:向访问哪个方法就直接加哪个方法。
    访问地址
    5)struts中默认的action配置【注意对应包的namespace】
    SSH框架教程完整版(附Github源码)_第6张图片
    6)struts中的常量配置
    • 页面乱码的配置:在后台数据提交给客户端的时候经常出现页面乱码的问题,可以每次在action里面进行转码request.setCharacterEncoding("UTF-8");但比较麻烦,因此可以在控制器struts.xml做常量配置,实现一次配置多页面使用的效果:
    • 动态调用的配置:如在struts中配合通配符使用时应该设置动态调用属性:
    • 调试模式的配置:设置调试模式,当页面或者服务器出现错误时,错误会显示在页面,方便开发的调试,亦称开发者模式:
    • web容器自动重新加载的配置:当修改struts.xml配置文件时,没必要每次都重新启动服务器,此时需要设置reload常量配置:
1.4 代理模式:

1)代理模式的使用有利于实现主体功能扩展,而代理角色对象不需要改变的情况,达到功能与实现的降耦合的优点:
SSH框架教程完整版(附Github源码)_第7张图片

2)动态代理模式:动态生成代理对象,根据传入的主题对象而动态的调用主题对象的方法,动态调用,而不是一次性生成固定的对象。【ps:代码】

  • 创建一个抽象的主题
package tmp;
/*
 * ChongZhi.java
 */
public interface ChongZhi {
	public void chongzhi(double money);
}

  • 创建不同的主题对象,比如创建微信充值对象和线上充值对象。
package tmp;

public class WeiXinChongZhi implements ChongZhi{

	@Override
	public void chongzhi(double money) {
		// TODO Auto-generated method stub
		System.out.println("微信充值话费"+money);
	}

}

package tmp;

public class InternetChongZhi implements ChongZhi{

	@Override
	public void chongzhi(double money) {
		// TODO Auto-generated method stub
		System.out.println("线上充值话费"+money);
	}

}

  • 创建动态代理的平台,必须继承自InvocationHandler
package tmp;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class ChongZhiHandler implements InvocationHandler{

	private Object realObject;
	
	public Object getRealObject() {
		return realObject;
	}

	public void setRealObject(Object realObject) {
		this.realObject = realObject;
	}

	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("充值代理平台");
		return method.invoke(realObject, args);
	}

}

  • 动态创建代理对象,执行对象方法。
package tmp;

import java.lang.reflect.Proxy;

public class ChongZhiTest {
	public static void main(String[] args) {

		ChongZhiHandler chongZhiHandler = new ChongZhiHandler();
		WeiXinChongZhi weiXinChongZhi = new WeiXinChongZhi();

		//动态生成代理对象
		chongZhiHandler.setRealObject(weiXinChongZhi);
		ChongZhi proxy = (ChongZhi) Proxy.newProxyInstance(WeiXinChongZhi.class.getClassLoader(), 
				weiXinChongZhi.getClass().getInterfaces(), chongZhiHandler);
		proxy.chongzhi(100.0);
	}
}

1.5 Struts拦截器的开发

  • 在SSH框架中,所有页面数据的处理都是由拦截器处理的。Struts拦截器的自定义开发可以为程序添加功能,在struts.xml中配置拦截器即可,无需改变原先的action类,类似于AOP编程。【Java EE—P180】

后续…(学习开发代码,包括struts标签库,文件上传和下载等)

2. Hibernate框架:

Hibernate框架知识点不复杂,博主记录较少ing~~~/

2.1 关于Hibernate和ORM框架的图解:

  • Hibernate实现数据的持久化(即将数据库获取的数据放在内存中,省去每次需要获取数据而去访问数据库的操作,提高效率)
  • 持久化的过程就是通过ORM框架实现的:

SSH框架教程完整版(附Github源码)_第8张图片

2.2 Hibernate体系结构

SSH框架教程完整版(附Github源码)_第9张图片

  • 解析:作为模型层/数据访问层,Hibernate通过配置文件和映射文件将Java对象或PO(Persistent Object,持久化对象)映射到数据库中的数据表,然后通过操作PO实现对数据库表的各种操作。(PO== POJO== VO)

2.3 Hibernate核心接口

1. Hibernate的核心接口主要有5个:Configuration、SessionFactory、Session、Transaction、Query。通过接口的使用,实现面向对象的数据库操作,包括持久化对象的存取和事务的控制等。

  • Configuration接口:负责读取Hibernate的配置信息(hibernate.cfg.xml),完成初始化工作。
  • SessionFactory接口:(Session的生产工厂)负责创建Session实例【SessionFactory一旦初始化完毕,即被赋予特定的配置信息,Configuration的变化不会影响已创建好的SessionFactory实例;SessionFactory实例保存了相应数据库配置的所有映射关系,同时负责维护当前的二级数据缓存与Statement Pool,是线程安全的,可由多个线程并发调用的】
  • Session接口:是持久化操作的基础,提供了众多的持久化方法,如save(),update(),delete(),query()等。它是非线程安全的,即一个Session实例同时只能由一个线程使用,并发调用会出现难以预估的错误。
  • Transaction接口:是Hibernate进行事务操作的接口。
  • Query接口:是Hibernate的查询接口,用于执行HQL语句。

参考SessionFactory文件和jsp文件进行学习:

package org.etspace.abc.factory;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;

/**
 * Configures and provides access to Hibernate sessions, tied to the
 * current thread of execution.  Follows the Thread Local Session
 * pattern, see {@link http://hibernate.org/42.html }.
 */
public class HibernateSessionFactory {

    /** 
     * Location of hibernate.cfg.xml file.
     * Location should be on the classpath as Hibernate uses  
     * #resourceAsStream style lookup for its configuration file. 
     * The default classpath location of the hibernate config file is 
     * in the default package. Use #setConfigFile() to update 
     * the location of the configuration file for the current session.   
     */
	private static final ThreadLocal threadLocal = new ThreadLocal();
    private static org.hibernate.SessionFactory sessionFactory;
	
    private static Configuration configuration = new Configuration();
    private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
    private static String configFile = CONFIG_FILE_LOCATION;

	static {
    	try {
			configuration.configure(configFile);
			sessionFactory = configuration.buildSessionFactory();
		} catch (Exception e) {
			System.err.println("%%%% Error Creating SessionFactory %%%%");
			e.printStackTrace();
		}
    }
    private HibernateSessionFactory() {
    }
	
	/**
     * Returns the ThreadLocal Session instance.  Lazy initialize
     * the SessionFactory if needed.
     *
     *  @return Session
     *  @throws HibernateException
     */
    public static Session getSession() throws HibernateException {
        Session session = (Session) threadLocal.get();

		if (session == null || !session.isOpen()) {
			if (sessionFactory == null) {
				rebuildSessionFactory();
			}
			session = (sessionFactory != null) ? sessionFactory.openSession()
					: null;
			threadLocal.set(session);
		}

        return session;
    }

	/**
     *  Rebuild hibernate session factory
     *
     */
	public static void rebuildSessionFactory() {
		try {
			configuration.configure(configFile);
			sessionFactory = configuration.buildSessionFactory();
		} catch (Exception e) {
			System.err.println("%%%% Error Creating SessionFactory %%%%");
			e.printStackTrace();
		}
	}

	/**
     *  Close the single hibernate session instance.
     *
     *  @throws HibernateException
     */
    public static void closeSession() throws HibernateException {
        Session session = (Session) threadLocal.get();
        threadLocal.set(null);

        if (session != null) {
            session.close();
        }
    }

	/**
     *  return session factory
     *
     */
	public static org.hibernate.SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	/**
     *  return session factory
     *
     *	session factory will be rebuilded in the next call
     */
	public static void setConfigFile(String configFile) {
		HibernateSessionFactory.configFile = configFile;
		sessionFactory = null;
	}
	/**
     *  return hibernate configuration
     *
     */
	public static Configuration getConfiguration() {
		return configuration;
	}

}
<%
    	Session mySession = HibernateSessionFactory.getSession();
    	Transaction transaction = mySession.beginTransaction();
    	Query query = mySession.createQuery("delete Bmb where bmbh=:bmbh");
    	query.setParameter("bmbh", "05");
    	int i = query.executeUpdate();
    	transaction.commit();
    	HibernateSessionFactory.closeSession();
    	
    	if(i==1){
    	%>
    		
    	<%
    	}else{
    	%>
    		
    	<%
    	}
     %>

2.4 Hibernate 查询语句—HQL

  • HQL的语句结构与SQL的语句结构基本相同!
  • HQL语句的执行依赖于Query实例,在创建Query实例时需要指定相应的HQL语句:
		//1.获取数据库会话连接
    	Session mysession = HibernateSessionFactory.getSession();
    	//2.建立查询,获取查询的List
    	Query query = mysession.createQuery("from Bmb");
    	List list = query.list();
  • HQL语句可以指定相应的位置参数(以 “?” 表示)或命名参数(以 " : 参数名"表示):
Query query = mysession.createQuery("from Bmb where bmbh=?");
Query query = mysession.createQuery("from Bmb where bmbh=:bmbh");
query.setString(0,"11");
query.setParameter("bmbh","12");
  • 执行HQL语句时 —> 对于查询类的HQL语句,调用Query实例的list()方法即可执行之;对于更新类的HQL语句,调用Query实例的executeUpdate()方法即可执行之。
		List list = query11.list(); //是一个Object集合或Object数组集合
		int m = query12.executeUpdate();
		int n = query13.executeUpdate();

2.5 Hibernate对象状态

  • Hibernate的对象状态,即实体对象的生命周期状态,包括3种:瞬时态、持久态、脱管态。

  • 瞬时态:未与Session实例关联的对象状态,与数据库记录无关。

Bmb bmb = new Bmb();
bmb.setBmbh("10");
bmb.setBmmc("学生会");

//此时的bmb处于瞬时态的对象
  • 持久态:已被Session实例关联,对应数据库中的一条记录,其变更将被保存到数据库中。
Bmb bmb = new Bmb();
bmb.setBmbh("10");
bmb.setBmmc("学生会");
Transaction tc = session.beginTransaction();
session.save(bmb); //bmb转化为持久态
tc.commit(); //提交事务,bmb被持久化到数据库中
bmb.setBmmc("公共部"); //bmb仍处于持久态中
  • 脱管态:由持久态对象转换过来,已不再跟Session实例关联,数据库中可能存在跟其对应的记录。
//以下方法均是关闭session实例的操作,bmb转化为脱管态
session.close();
HibernateSessionFactory.closefSession();
  • 从实体对象是否被纳入Hibernate实体管理容器的角度加以区别,瞬时态和脱管态的对象称为值对象(VO),处于持久态的对象称为持久对象(PO)。

2.6 Hibernate批量处理

  • Hibernate批量处理包括批量插入、批量修改、批量删除

1. 批量插入:2种实现 >>Hibernate缓存 、 调用JDBC API

  • Hibernate缓存实现批量插入:【步骤:(1)在配置文件hibernate.cfg.xml中设置批量插入的尺寸大小;(2)关闭二级缓存提高存取效率;(3)编码实现】
		
		3
		
		false
	 <%
    	Session mySession = HibernateSessionFactory.getSession();
    	Transaction transaction = mySession.beginTransaction();
    	for(int i=12;i<18;i++){
    		Bmb bmb= new Bmb();
    		bmb.setBmbh(String.valueOf(i));
    		bmb.setBmmc("部门"+i);
    		//将对象持久化
    		mySession.save(bmb);
    		//缓存3个的时候将数据批量插入到数据库中
    		if((i-2)%3==0){
    			mySession.flush(); //插入当前批的数据,实际上还没真正插入到数据库中
    			mySession.clear(); //释放缓冲区,供下一批数据缓存
    		}
    	}
    	transaction.commit(); //真正提交更新的数据库的操作
    	HibernateSessionFactory.closeSession();
     %>
  • JDBC API(Hibernate 3.3.2开始已被弃用)

2. 批量修改:2种实现>>Hibernate直接处理 、 调用JDBC API

  • Hibernate直接处理(无需修改配置文件)
		Session mySession = HibernateSessionFactory.getSession();
    	Transaction transaction = mySession.beginTransaction();
    	Query query = mySession.createQuery("update Bmb set bmmc='投资部' where bmbh>? ");
    	query.setString(0, "04");
    	int i=0;
    	i = query.executeUpdate();
    	transaction.commit();
    	HibernateSessionFactory.closeSession();

3. 批量删除: 2种实现>>Hibernate直接删除 、 调用JDBC API

  • Hibernate 直接删除
		Session mySession = HibernateSessionFactory.getSession();
    	Transaction transaction = mySession.beginTransaction();
    	Query query = mySession.createQuery("delete Bmb where bmbh>='50' ");
    	int i=0;
    	i = query.executeUpdate();
    	transaction.commit();
    	HibernateSessionFactory.closeSession();

2.7 Hibernate事务管理

  1. 事务的4个特性:原子性、一致性、隔离性、持久性
  2. Hibernate的事务管理与调度功能是委托给底层的JDBC或JTA(Java Transaction API)来实现的。
  • 基于JDBC的事务管理:在调用sessionFactory.openSession()时,Hibernate会初始化数据库链接,并将AutoCommit设置为关闭状态false,所以在Hibernate中没有执行事务的commit()操作时,更新的数据是不会同步到数据库的。
  • 基于JTA的事务管理:JDBC是单个数据源操作的,由Connection来管理事务的生命周期。而JTA事务的管理则有2个重要的特性:分布式+多数据源,且只能由事务管理器来管理,JTA可以横跨多个JDBC Connection 生命周期,即可以管理多个Session实例,而JDBC只能同时管理一个Session实例。Hibernate的默认事务管理机制是JDBC 管理机制。

3. Spring框架

3.1 Spring 框架简介:

  1. Spring框架具有简单、可测试和松耦合的特征;Spring框架用来解决企业应用开发中的臃肿、低效和复杂性问题。其主要使用基本的JavaBean即可胜任EJB完成的工作。
  2. Spring的架构模式类似于设计模式中的工厂模式,核心机制是依赖注入(DI),也叫控制反转(IoC)。所谓DI,就是在程序运行过程中,当需要调用另一个对象协助时,无须在代码中直接创建该对象,而是依赖于外部容器的注入,换言之,DI机制将对象间的依赖关系交由外部容器管理,而程序内部只负责接口的控制和使用,从而实现控制权从内部代码到外部容器的转移。

3.2 Spring开发能力的添加步骤(以Myeclipse2017为例子)

  1. 右击项目–>properties–>搜索spring–>在单选框前选择spring–OK.
  2. 配置完成,在项目的src下多出了一个applicationContext.xml文件.
  3. 在Project-Explorer 视图下能看到已添加的spring的 jar包和Bean.

3.3 Spring依赖注入

  1. 设置注入【调用者通过setter方法来注入被调用者实例的方式;该方式是在调用 无参构造函数(方法) 创建默认的Bean实例后,再调用相应的setter方法设置属性值】,实例:
public interface People {
	public void speak();
}

public interface Language {
	public String type();
}

public class Language_English implements Language{

	@Override
	public String type() {
		return "Chinese/India speak English too.";
	}

}

public class People_Chinese implements People{
	private Language language;
	public People_Chinese() {
		// TODO Auto-generated constructor stub
	}
	@Override
	public void speak() {
		System.out.println(language.type());
	}

	public void setLanguage(Language language) {
		this.language = language;
	}

}

applicationContext.xml配置信息如下:

		
		
			
			
		
		
		

测试类关键代码:

		//1.获取配置文件信息
		ApplicationContext ac = new FileSystemXmlApplicationContext("src/applicationContext.xml");
		//2.获取对应的Bean并做输出测试
		People people = null;
		people = (People) ac.getBean("people_chinese");
		people.speak();

  1. 构造注入【调用者利用 构造函数(方法) 来注入被调用者实例的方法–在创建Bean时就完成了被调用者实例的注入!】

构造注入关键代码:(在设置注入的基础上做调用者类的变动)

public class People_India implements People{
	private Language language;
	
	/**
	 * 再次无参构造函数不能省略!!!
	 */
	public People_India() {
		// TODO Auto-generated constructor stub
	}
	public People_India(Language language) {
		this.language = language;
	}
	@Override
	public void speak() {
		System.out.println(language.type());
	}

}

applicationContext.xml配置信息:

				
		
			
		

3.4 Spring 关键配置

1. Bean的依赖配置
(1)在设置注入中,在元素添加相应的< property >子元素;
(2)在构造注入中,在元素添加相应的< constructor-arg >子元素,在子元素中还应设置index属性以表明该元素对应到构造函数(方法)中的哪一个参数(第一个参数的index=“0”),若只有一个参数,可不用设置index属性。

		
			
		

(3)若注入的属性的类型是List、Set或Map,道理同对象的注入一样(将对象的定义改为List/Set/Map的定义,xml配置如下:)

		
			
				
					...
					...
					...
				
			
		

Set的配置跟List类似


			
				
					
						...
					
					
						...
					
					
						...
					
				
			

2. Bean的作用域设置

  • singleton作用域:该Bean处于单例模式 — Spring容器创建该Bean的唯一实例并存储到单例缓存中,对该Bean的请求与引用均将返回缓存中的同一个对象。2中配置方法:


  • prototype作用域:该Bean处于原型模式 — 每次对Bean的调用Spring容器都会产生一个新的实例,每次返回的对象实例都是不同的,相当于每次都new一个对象。

  • request作用域:针对该Bean的每个HTTP请求,容器产生一个新的实例,该实例仅在当前的HTTP request作用域内有效。
  • session作用域:针对该Bean的每个HTTP请求,容器产生一个新的实例,该实例仅在当前的HTTP session作用域内有效。
  • global session作用域:全局session作用域。

默认情况下,Spring中的Bean均为单例模式,即作用域为singleton。

3. Bean的生命周期方法设置

所谓的Bean的生命周期方法设置,就是在Spring容器创建一个Bean实例后或删除一个Bean实例前,自动调用Bean中的某个方法以完成相应的处理过程

		
			
			
		
public class People_Chinese implements People{
	private Language language;
	public People_Chinese() {
		// TODO Auto-generated constructor stub
	}
	@Override
	public void speak() {
		System.out.println(language.type());
	}

	public void setLanguage(Language language) {
		this.language = language;
	}
	
	public void initialize(){ //在实例注入后调用
		System.out.println("初始化工作完毕!!!");
	}

	public void cleanup(){ //在撤出实例前调用
		System.out.println("Spring容器准备删除Bean,清理工作完毕!!!");
	}
}

public class Spring_Test2 {
	public static void main(String[] args) {
		//测试Spring的设置注入方式
		//1.获取配置文件信息
		AbstractApplicationContext aac = new FileSystemXmlApplicationContext("src/applicationContext.xml");
		//2.获取对应的Bean并做输出测试
		People people = null;
		people = (People) aac.getBean("people_chinese");
		people.speak();
		aac.registerShutdownHook(); //注销
	}
}

运行结果:
运行结果

3.5 Spring 核心接口

  1. BeanFactory接口:(1)该接口的常用实现是XmlBeanFactory,XmlBeanFactory根据XML配置文件中的Bean的定义装载Bean;(2)BeanFactory只从XML配置文件中读取Bean的定义信息,但Bean并未被实例化,即延迟加载;(3)2种创建实例的方法:
/*
 * 法一:传递一个java.io.InputStream对象给XmlBeanFactory的构造函数创建实例
 */
InputStream is = new FileInputStream("applicationContext.xml");
BeanFactory bf = new XmlBeanFactory(is);
MyBean mb = bf.getBean("myBean"); //获取Bean

/*
 1. 法二:传递一个ClassPathResource对象给BeanFactory的构造函数创建
 */
 ClassPathResource cpr = new ClassPathResource("applicationContext.xml");
 BeanFactory bf = new XmlBeanFactory(cpr);
 MyBean mb = bf.getBean("myBean");
  1. ApplicationContext接口: (1)Spring的高级容器,对BeanFactory进行适当的扩充,提供了更多的功能。(2)ApplicationContext接口在上下文启动之后便预先加载所有的单例Bean,这样在需要时即可直接使用相应的Bean实例;(3)3种常用实现:
/* 
 1. 法一:ClassPathXmlApplicationContext--->从类路径中的XML配置文件载入上下文定义信息(把上下文定义文件当成类路径资源)
 */
  ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
  MyBean mb = ac.getBean("myBean");
 
/* 
 2. 法二:FileSystemXmlApplicationContext--->从文件系统中的配置文件载入上下文定义信息
 */
  ApplicationContext ac = new FileSystemXmlApplicationContext("c:\\applicationContext.xml"); //亦可用相对路径,如:"src/applicationContext.xml"
  MyBean mb = ac.getBean("myBean");
  
/* 
 3. 法三:XmlWebApplicationContext--->从Web系统中(即Web应用目录 WEB-INF中的XML配置文件载入上下文定义信息)
 */
  ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletContext() );
  MyBean mb = ac.getBean("myBean");

3.6 Spring AOP

1. AOP介绍:AOP(Aspect-Oriented Programming,面向切面编程),其目的在于保证不修改源代码的前提下为系统业务组件的有关方法添加某种通用的功能,如安全控制,权限检查,事务管理,异常处理等。

2. 逻辑术语:关注点、连接点、增强(包括前置增强+后置增强+异常增强+环绕增强)、切入点、切面、引入、目标对象、AOP代理(即对目标对象进行增强的对象)、织入(2种方式:编译时增强+运行时增强,Spring是运行时增强的)

3. 实现机制:静态代理、动态代理
(1)静态代理:代理类与被代理类需实现同一个接口;代理类提供服务(如权限检查),在需要时呼叫被代理类;

public interface IDoSomething {
	public void executeFuction1();
	public void executeFuction2();
	public void executeFuction3();
}
public class DoSomething implements IDoSomething{

	@Override
	public void executeFuction1() {
		// TODO Auto-generated method stub
		System.out.println("Execute function1...");
	}

	@Override
	public void executeFuction2() {
		// TODO Auto-generated method stub
		System.out.println("Execute function2...");
	}

	@Override
	public void executeFuction3() {
		// TODO Auto-generated method stub
		System.out.println("Execute function3...");
	}

}

public class DoSomethingProxy implements IDoSomething{
	private DoSomething doSomething;

	public DoSomethingProxy(DoSomething doSomething) {
		// TODO Auto-generated constructor stub
		this.doSomething = doSomething;
	}
	@Override
	public void executeFuction1() {
		// TODO Auto-generated method stub
		checkAuthority();
		doSomething.executeFuction1();
	}

	@Override
	public void executeFuction2() {
		// TODO Auto-generated method stub
		checkAuthority();
		doSomething.executeFuction2();
	}

	@Override
	public void executeFuction3() {
		// TODO Auto-generated method stub
		checkAuthority();
		doSomething.executeFuction3();
	}

	public void checkAuthority(){
		System.out.println("Check the privileges...");
	}

}

public class TestDoSomethingProxy {
	public static void main(String[] args) {
		IDoSomething iDoSomething = new DoSomethingProxy(new DoSomething());
		iDoSomething.executeFuction1();
		iDoSomething.executeFuction2();
		iDoSomething.executeFuction3();
	}
}

(2)动态代理:是一个范类代理;需运行在JDK1.3及以上的环境下;包括JDK动态代理(实现接口InvocationHandler的目标对象的代理)和CGLib动态代理(不实现接口的目标对象的代理);一下以JDK动态代理为例子。

package org.etspace.abc.proxy;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationHandler; //注意引用该包的此接口

public class CheckAuthorityProxy implements InvocationHandler{
	private Object object;

	public CheckAuthorityProxy(Object object) {
		// TODO Auto-generated constructor stub
		this.object = object;
	}

	/**
	 * Use the method bind() to load a new proxy instance of one class.
	 * @return
	 */
	public Object bind(){
		return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces()
				, this);

	}

	/* (non-Javadoc)
	 * invoke()回调方法负责处理被代理类方法的调用;
	 * 第1个参数是调用方法的代理实例,第2个参数是被代理类实例的方法名,第3个参数是相应方法的参数数组
	 * invoke()方法会传入被代理对象的方法名和参数,通过method.invoke(obj,args)调用被代理类实例的方法,返回的结果即为被代理类的方法返回的结果
	 * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// TODO Auto-generated method stub
		//1.检查权限
		//2.调用invoke方法
		Object result = null;
		checkAuthority();
		result = method.invoke(object, args);

		//3.返回调用结果
		return result;
	}

	public void checkAuthority(){
		System.out.println("Check the privileges...");
	}

}

public class TestCheckAuthorityProxy {
	public static void main(String[] args) {
		CheckAuthorityProxy checkAuthorityProxy = new CheckAuthorityProxy(new DoSomething());
		IDoSomething iDoSomething = (IDoSomething) checkAuthorityProxy.bind();
		iDoSomething.executeFuction1();
		iDoSomething.executeFuction2();
		iDoSomething.executeFuction3();
	}
}

4. Spring AOP的基本应用

Spring AOP是基于动态代理机制实现的!!!

(1)增强(Advice)类的设计: 支持多种增强类型,例如前置增强(实现MethodBeforeAdvice接口,覆盖before()方法,在before()方法中编写增强的服务代码)

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

/**
 * Design the Class of Advice
 */
public class AdviceBeforeDoSomething implements MethodBeforeAdvice{

	@Override
	public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("Check the Privileges...");
	}

}

...
...


			
			
			
			
			
			
				  
				  
				  		org.etspace.abc.inte.IDoSomething
				  
				  
				  
				  		
				  
				  
				  
				  	
				  		
				  		doSomethingAdvisor1
				  		doSomethingAdvisor2
				  	
				  
			
			...
			...
public static void main(String[] args) {
		ApplicationContext ac = new FileSystemXmlApplicationContext("src/applicationContext.xml");
		IDoSomething ids = (IDoSomething) ac.getBean("doSomethingProxy");
		ids.executeFuction1();
		ids.executeFuction2();
		ids.executeFuction3();
	}

(2)增强器(Advisor)的使用: 增强器实质上就是切入点(Pointcut)和增强(Advice)的适配器,将二者结合起来,决定在何处进行何种增强 ;Spring AOP中有2种增强器----> NameMatchMethodPointcutAdvisorRegexpMethodPointcutAdvisor

  • 示例:在以上的配置文件基础上添加一下配置代码(*3和.*3都是指定名称以 "3"结尾的方法)

		
		
			
				*3
			
			
				
			
		
		
		
			
				.*3
			
			
				
			
		
		
  • 注:本小节(4)中AOP框架的应用的底层实现就是小节(3)中AOP的实现机制原理,切勿理解为不同的实现方法!!!

你可能感兴趣的:(Java编程基础,SSH那些事,SSH框架)