1. Spring
1.1 概述
Spring就是一个创建对象的工厂,实现了从new到反射的转变
Spring也是一个容器,她用来创建、管理和维护对象的状态及各对象之间的依赖关系(IOC)
Spring的两大核心 AOP/IOC,在工厂使用了代理的设计模式
AOP是面向切面编程,JAVA是面向对象编程
1.2 优点
- 非侵入式设计:Spring是一种非侵入式(non-invasive)框架,他可以使应用程序代码对框架的依赖最小化。
- 侵入式设计:用户代码对框架的依赖,表现为用户代码需要继承框架提供的类,这些代码不能再框架外使用,不利于代码的复用,但可以使用户跟框架更好的结合,更容易,充分的利用框架提供的功能。
- 非侵入式:没有过多的依赖,不需要用户代码引入框架代码的信息,从类的编写者角度来看,察觉不到框架的存在,方便的迁移到其他地方,但是与用户代码互动的方式可能就比较复杂。
- 方便解耦,简化开发:Spring就是一个大工厂,可以将所有对象的创建和依赖关系的维护工作都交给Spring容器的管理,大大的降低了组件之间的耦合性。
- 支持AOP:Spring提供了对AOP的支持,它允许将一些通用任务,如安全、事务、日志等进行集中式处理,从而提高了程序的复用性。
- 支持声明式事务处理:只需要通过配置就可以完成对事务的管理,而无需手动编程。
- 方便程序的测试:Spring提供了的对Junit4的支持,可以通过注解方便的测试Spring程序。
- 方便继承各种优秀框架:Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等的支持)。
- 降低Java EE API的使用难度:Spring对Java EE开发中非常难用的一些API(如JDBC、JavaMail等),都提供了封装,使这些API应用难度大大降低
1.3 组成
组成Spring框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现,每个模块的功能如下:
- 核心容器:核心容器提供Spring框架的基本功能。核心容器的主要组件是BeanFactory,它是工厂模式的实现。BeanFactory使用控制反转(IOC)模式将应用程序的配置和依赖性规范与实际的用用程序代码分开
- Spring上下文:Spring上下文是一个配置文件,向Spring框架提供上下文信息。Spring上下文包括企业服务,例如JNDI、EJB、电子邮件、国际化、校验和调度功能。
- Spring AOP:通过配置管理特性,Sptring AOP模块直接将面向切面的编程功能集成到了Spring框架中。所以可以很容易的使Spring框架管理任何支持AOP的对象。Spring AOP 模块为基于Spring的应用程序中的对象提供了事务管理服务。通过使用Spring AOP,不用依赖组件,就可以将声明式事务管理集成到应用程序中。
- Spring ADO:JDBC DAO抽象层提供了有意义的异常层次结构,可用改结构来管理异常处理和不用数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大的降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO的面相JDBC的异常遵从通用的DAO异常层次结构
- Spring ORP:Spring 框架插入了若干个ORM框架,从而提供了ORM的对象关系工具,其中包括JDO、Hibernate和iBatis SQL Map。所有这些都遵从Spring的通用事务和DAO异常层次结构。
- Spring Web模块:Web上下文模块建立在应用程序上下文模块智商,为基于Web的应用程序提供了上下文。所以,Spring框架支持与Jakarta Struts的继承。Web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
- Spring MVC框架:MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略结构,MVC框架便成为高度可配置的,MVC容纳了大量视图技术,其中包括JSP、Velocity、Tiles、Itext和POI。
2.IOC
2.1 分析实现
使用IOC之前的代码
public interface UserDao {
public void getUser();
}
public class UserDaoImpl implements UserDao {
@Override
public void getUser() {
System.out.println("获取用户数据");
}
}
public interface UserService {
public void getUser();
}
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImpl();
@Override
public void getUser() {
userDao.getUser();
}
}
public class Test {
@Test
public void test() {
UserService service = new UserviceImpl();
service.getUser();
}
}
使用IOC之后的代码
public interface UserDao {
public void getUser();
}
public class UserDaoImpl implements UserDao {
@Override
public void getUser() {
System.out.println("获取用户数据");
}
}
public class UserDaoImpl implements UserDao {
@Override
public void getUser() {
System.out.println("获取用户数据1");
}
}
public class UserDaoImpl implements UserDao {
@Override
public void getUser() {
System.out.println("获取用户数据2");
}
}
public interface UserService {
public void getUser();
}
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao (UserDao userDao) {
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
public class Test {
@Test
public void test () {
UserService service = new UserServiceImpl();
service.setUserDao(new UserDaoImpl1());
service.getUser();
service.serUserDao(new UserDaoImpl2());
service.getUser();
}
}
2.2 IOC本质
控制反转 IOC (Inversion of Control),是一种设计思想,DI (依赖注入)是实现 IOC 的一种方法,也有人认为 DI 只是 IOC 的另一种说法。没有 IOC 的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方。
IOC 是 Spring 框架的核心内容,使用多种方式完美的实现了 IOC ,可以使用 XML 配置,也可以使用注解。
Spring 容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从 IOC 容器中去除需要的对象。
控制反转是一种通过描述(XML 或注解)并通过第三方去生产或获取特定对象的方式。在 Spring 中实现控制反转的是 IOC 容器,其实现方法是依赖注入 DI (Dependency injection)。
2.3 注入方式
-
通过注解的方式注入
@Compoment
@Service
@Aspect
-
通过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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="user" class="guobf.spring.User" /> </beans>
-
有参构造注入
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 通过下标 --> <bean id="user" class="guobf.spring.User"> <contructor-arg index="0" value="guobf" /> </bean> <!-- 通过类型 --> <bean id="user1" class="guobf.spring.User"> <contructor-arg type="java.lang.String" value="guobf"/> </bean> <!-- 通过参数名 --> <bean id="user2" class="guobf.spring.User"> <contructor-arg name="name" value="guobf" /> </bean> </beans>
-
其他注入
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="user" class="guobf.spring.User"> <!-- 数组 --> <property name="books"> <array> <value>1</value> <value>2</value> <value>3</value> </array> </property> <!-- List --> <property name="books2"> <list> <value>1</value> <value>2</value> <value>3</value> </list> </property> <!-- Map --> <property name="card"> <map> <entry key="中国邮政" value="111"/> <entry key="建设" value="222"/> </map> </property> <!-- Set --> <property name="books2"> <set> <value>1</value> <value>2</value> <value>3</value> </set> </property> <!-- Null --> <property name="wife"><null/></property> </bean> </beans>
-
2.4 Bean作用域
- Singleton:在 IOC 容器中仅存在一个 Bean 实例,以单例形式存在
- Prototype:每次从容器调用 Bean 时,都返回一个新的实例
- Request:每次 HTTP 请求都会创建一个新的 Bean ,该作用域仅适用于 WebApplicationContext
- Session:同一个 HTTP Session共享一个 Bean ,该作用域仅适用于 WebApplicationContext
2.5 装配机制
1.通过xml显式配置
<bean id="user" class="guobf.spring.User" />
2.通过JAVA代码显式配置
@Component("user")
3.阴式的bean发现机制和自动装配
-
byName
public class Student { public String name = "student"; // getter setter // contructor } public class User { private String name; private Student student; // getter setter // contructor } <bean id="student" class="guobf.spring.test.pojo.Student"/> <bean id="person" class="guobf.spring.test.pojo.Person" autowire="byName"> <property name="name" value="guobf"/> </bean>
-
byType
public class Student { public String name = "student"; // getter setter // contructor } public class User { private String name; private Student student; // getter setter // contructor } <bean id="student" class="guobf.spring.test.pojo.Student"/> <bean id="person" class="guobf.spring.test.pojo.Person" autowire="byType"> <property name="name" value="guobf"/> </bean>
-
注解
@Autowired 是按类型自动转配的,不支持id匹配 @Qualifier @Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配,不能单独使用 @Resource @Resource如有指定的name属性,先按该属性进行byName方式查找装配,其次再进行默认的byName方式进行装配,如果以上都不成功,则按byType的方式自动装配
2.6 使用注解开发
<!--指定注解扫描包-->
<context:component-scan base-package="guobf.spring"/>
@Component("user") ---类
@Value("aaa") ---属性值
3.AOP
3.1 静态代理
public interface UserDao {
public void query();
}
public class UserDaoImpl implements UserDao {
@Override
public void query() {
System.out.println("UserDaoImpl[query]方法被调用")
}
}
public class ProxyByCustom implements UserDao {
private UserDaoImpl userDaoImpl;
// 将需要打印的日志硬编码到代码中
@Override
public void query() {
before();
userDaoImpl.query();
after();
}
public void before() {
System.out.println("查询方法前的日志");
}
public void after() {
System.out.println("查询方法后的日志");
}
}
3.2 动态代理
-
基于接口的动态代理 —> JDK 动态代理
// 抽象角色:租房 public interface Rent { public void rent(); } // 具体实现角色 public class Host implements Rent { @Override public void rent() { System.out.println("房东要租房"); } } import java.lang.reflect.Proxy; // 代理类对象 public class ProxyInvocationHandler implements InvocationHandler { private Object target; // 通过set方法指定需要被代理的对象 public void setTarget(Object target) { this.target=target; } // 获取代理类对象 public Object getProxy() { return Proxy.newProxyInstance(this.getClass().getClassLoader(), Object.class.getInterfaces(), this); } public void log(String className, String methodName, long l1, long l2) { System.out.println("执行" + className + "中的" + methodName + "方法,耗时:" + String.valueOf(l2 - l1 )); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long start = System.currentTimeMillis(); Object result = method.invoke(target, args); long end = System.currentTimeMillis(); log(target.getClass().getSimpleName(), method.getName(), start, end); return result; } } // 测试 public class Test { public static void main(String[] args) { //真实角色 Host host = new Host(); //代理实例的调用处理程序 ProxyInvocationHandler pih = new ProxyInvocationHandler(); pih.setRent(host); //将真实角色放置进去! Rent proxy = (Rent)pih.getProxy(); //动态生成对应的代理类! proxy.rent(); } }
-
基于类的动态代理 —> cglib
public class CglibInvocationHandler implements MethodInterceptor { private Object target; public void setTarget(Object target) { this.target = target; } public Object getProxy() { Enhancer enhancer = new Enhancer(); //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类 enhancer.setSuperclass(target.getClass()); enhancer.setCallback(this); return enhancer.create(); } public void log(String className, String methodName, long l1, long l2) { System.out.println("执行" + className + "中的" + methodName + "方法,耗时:" + String.valueOf(l2 - l1 )); } public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { long start = System.currentTimeMillis(); Object result = method.invoke(target, objects); long end = System.currentTimeMillis(); log(target.getClass().getSimpleName(), method.getName(), start, end); return result; } }