学习Spring札记二
一
动态代理模式
静态代理:代码复用不高,将来维护时难
动态代理:静态代理上提供的,因为代理比较常用,JDK提供了一套生成代理类的方式proxy类(遇到什么问题先看JDK有没有提供解决方法),动态代理的特点是把增强的功能包装成一个类,这个类要实现InvocationHandler接口,看到InvocationHandler要条件反射想到动态代理。代理类实现增强功能的类都需要委托类做属性,因为需要它们来做参数,写到有参构造里。不论静态、动态都需要!
实例代码
1.dao.impl下建立UserDaoFactory类
public class UserDaoFactory{
UserDao userDao = new UserDaoImplForMysql(); //这个委托类,作为回调函数的参数。学习框架后,这样把类作为属性,传值的方式越常见
public static UserDao getInstance(){
UserDao proxy =Proxy.newProxyInstance(
UserDao.class.getClassLoader(), //获得字节码
UserDaoImplForMysql.class.getInterfaces(), //代理类和委托类实现同一接口(相似性),这里是获取代理类、委托类的接口
new LogHandler(userDao) //LogHandler类是代理类,userDao是委托类,在这里把他们动态组合成一个代理,所以这是动态代理的重点(这两个类需要分别实现)
);
return proxy;
}
public static void main(String[ ] args){
UserDao dao = UserDaoFactory.getInstance(); //UserDaoFactory是不用new的,因为getInstance方法是static的,只需要通过UserDaoFactory来引用即可,不用new
dao.add();
}
}
2.建立一个handler包,里面有一个LogHandler类,内容如下
public class LogHandler implements InvocationHandler{ //实现InvocationHandler接口,这是个动态代理类
public Object obj; //委托类对象的引用
public LogHandler(Object obj){ //有参构造 ,为了嵌套委托类而写
super();
this.obj = obj;
}
public Object invoke(Object proxy,Method method,Object[ ] args)throws Throwable { //实现InvocationHandler接口会实现invoke方法
System.out.println("系统日志!!!");
method.invoke(obj,args); //这里的invoke方法可以这样理解,客户类action调用UserDaoFactory的getInstance方法,这个方法的Proxy.newProxyInstance里的第三个参数去调用此invoke方法,然后这个方法返回给Proxy.newProxyInstance,再返回给getInstance,再一层层向上返回。先一层层向下调用 ,然后按顺序再返回。
return null;
}
}
3.另外还需要接口UserDao,UserDaoImplForMysql,和其它实例中的一样。实例结束,可以运行main方法测试
解释一下动态代理
动态代理是通过proxy对象把委托类(UserDaoImplForMysql) 和代理类(LogHandler) 组合了起来!!
action调用的是Factory中的proxy对象的newProxyInstance方法,它里面的回调函数调用代理类来执行作为参数的委托类“new LogHandler(userDao)” userDao委托类的接口,LogHandler代理类。(回调函数要好好练一练)
动态代理默认会景程委托类的所有方法,如果你在UserDao接口里添加del方法,并且它的实现类也实现了该方法,在main方法添加dao.del();执行时会也在del外增强LogHandler的功能。
动态代理的proxy对象的详细解说
共3个参数,第一个classloader,第二个是获取接口(可以对这个接口下的实现类造成影响),第三个是回调函数,它的参数是委托类。在当前类显示的是userDao,在LogHandler类里是obj引用。$ProxyN 是jdk制作出来的代理类的命名规则。看到控制台打印这种形式的应该知道这是JDK的代理类。
代理类两个原则:相似性和增强
动态代理:委托类必须有接口,代理类才能和委托类相似。因为接口就是对于这个类的描述。就像一张图纸定义这个类的。缺点是必须和有接口。
只要是远程方法之间调用,不同语言之间沟通,两台机器之间沟通。这些东西全都是代理。所以代理模式非常重要,它是一个思维的基础,没有这个思维的基础,脑海里面就建立不起来这个模型。
————————动态代理 end ——————————————————
二
Spring正题——————
什么项目适合用Spring?
中型最合适,大型分布式项目用EJB
Spring+webservice也可以实现分布式项目(分布式项目是指,一个子系统在北京,另一个子系统在海南这样的项目)
Spring的helloworld代码start——————
1.下载jar包(jar包中docs/MVC-step-by-step是教SpringMVC的)
它的lib包下有好多其它的框架的包,因为Spring可以和它们整合,Spring自己的jar包则放在了dist文件夹下面(一般下载下来的jar包,核心文件常会放在dist文件夹下)
spring.jar包需要拷贝,modules文件夹下面的jar包是把spring.jar包分解开的小jar包,你可以看情况选择用哪个。
spring-sources.jar也一起拷贝到项目中。
a) 把spring.jar和spring-sources.jar拷贝到项目下
b) 把jarkarta-commons的commons-logging.jar拷贝到项目下
2.src下建立beans.xml,它的内容没必要记,要拷贝,自己写容易写错
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="userDao" class="com.bjsxt.dao.UserDao" lazy-init="true"></bean> //这个bean要对应到项目中,要写个userDao类,默认是饿加载,要写lazy-init="true"变成懒加载
</beans>
3.建立dao包,包下建立UserDao类
public class UserDao{
public UserDao(){
System.out.println("init......");
}
public void add (){
System.out.println("Hello Spring");
}
}
4.建立test包,包下建立Test类,来创建spring提供的IOC容器,当然,不是我们自己手写,和代理一样,JDK有提供相关API(JAVA这么规范、强大的语言,很多都提供了接口,其实很简单)
public class Test{
//IOC像一个大工厂,单例、工厂、代理、IOC模式它都包括
public static void main(String[ ] args){
ApplicationContext ac = new ClassPathXmlApplicationContext(
new String[ ] {"beans.xml"} //AC容器在读取beans.xml配置文件
);
UserDao userDao = (UserDao) ac.getBean("userDao"); //AC容器从beans.xml中找到userDao,通过反射实例化UserDao,然后使用它的方法。通过IOC容器来统一实例化,达到控制对象与对象之间的关系,而不是你想实例化谁就实例化谁。
userDao.add();
}
}
Spring的helloword end——————————