MyBatis框架是一个持久化的框架、负责数据访问
Spring MVC是Spring框架中的一个模块,负责控制器的管理
Spring是一个轻量级的容器框架
轻量级:针对EJB(Enterprise Java Bean)。
容器框架:Spring就是一个大工厂。程序中的工厂是用来生产对象的。容器就是一个生产、管理、维护对象的工厂
Spring框架的核心技术: IoC AOP
IoC(Inversion of Control): 控制反转
AOP: 面向切面编程 (面向方面编程)
Spring是一个基于Ioc和AOP的轻量级饿的容器框架
Spring是由七个组件构成的。在使用Spring框架时,七个组件可以组合使用,也可以拆分使用
1.依赖注入 : DI (Dependency Injection)
在运行期: 由外部容器动态地将依赖对象注入到组件中
** 2.控制反转: IoC (Inversion of Control)**
所谓控制反转就是应用本身不负责依赖对象的创建及维护,依赖对象的创建及维护由外部容器来负责的。这样控制就由应用本身转移到了外部容器,控制权的转移就是所谓控制反转。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,所谓控制反转就是:获得依赖对象的方式反转了。
依赖: 在程序开发中,对象之间存在依赖关系,比如:BIZ(业务层)依赖于DAO(数据访问层),Controller(控制层)依赖于BIZ程序开发是分层进行的。高内聚,低耦合。
public interface GoodsDAO {
public void save();
}
public class GoodsDAOImpl implements GoodsDAO {
@Override
public void save() {
System.out.println("GoodsDAOImpl.save() is called....");
}
public class GoodsBIZ {
private GoodsDAO goodsDAO = new GoodsDAOImpl();
public void save(){
System.out.println("GoodsBIZ.save() is called...");
this.goodsDAO.save();
}
在GoodsBIZ类中,依赖于GoodsDAOImpl对象,它是以主动获取的方式获得依赖对象。new GoodsDAOImpl();这样,GoodsBIZ主动创建DAO,BIZ与DAO耦合高
public interface GoodsDAO {
public void save();
}
public class GoodsDAOImpl implements GoodsDAO {
@Override
public void save() {
System.out.println("GoodsDAOImpl.save() is called....");
}
public class GoodsBIZ {
private GoodsDAO goodsDAO;
public GoodsDAO getGoodsDAO() {
return goodsDAO;
}
public void setGoodsDAO(GoodsDAO goodsDAO) {
this.goodsDAO = goodsDAO;
}
public void save(){
System.out.println("GoodsBIZ.save() is called...");
goodsDAO.save();
}
在GoodsBIZ类中,依赖于GoodsDAO接口,而接口只是一个规范,它是以被动接收的方式,获得依赖对象。依赖对象的创建由外部容器指定,BIZ与DAO耦合低。
测试:
public class SpringText {
public static void main(String[] args) {
GoodsBIZ goodsBIZ = new GoodsBIZ();
GoodsDAO goodsDAO = new GoodsDAOImpl();
goodsBIZ.setGoodsDAO(goodsDAO);
goodsBIZ.save();
}
GoodsBIZ由主动获取变成了被动接收,控制权发生了变化,这个变化就叫控制反转,因为当前的控制权变成了被动接收,依赖对象由外部容器给GoodsBIZ注入。是通过setGoodsDAO(…)进行注入的goodsBIZ.setGoodsDAO(goodsDAO); 这句话就叫依赖注入。
在src目录下有个applicationContext.xml文件,他是Spring框架的核心配置文件
在Spring容器中创建对象,在applicationContext.xml文件中配置
<bean name="goodsDAO" class="com.zpark.tea_mgr.dao.impl.GoodsDAOImpl"/>
ApplicationContext接口
ClassPathXmlApplicationContext:基于类路径的方式加载Spring配置文件
ApplicationContext context =
new ClassPathXmlApplicationContext("/applicationContext.xml");
GoodsDAO goodsDAO = (GoodsDAO) context.getBean("goodsDAO");
goodsDAO.save();
<bean name="goodsBIZ" class="com.zpark.tea_mgr.biz.GoodsBIZ"></bean>
<bean name="goodsBIZ" class="com.zpark.tea_mgr.biz.GoodsBIZ">
<property name="goodsDAO"> <!-- GoodsBIZA有个属性叫goodsDAO -->
<ref bean="goodsDAO"/> <!—依赖。引用了上面那个bean(1) Dao注入BIZ-->
</property>
</bean>
@SuppressWarnings("resource")
ApplicationContext context =
new ClassPathXmlApplicationContext("/applicationContext.xml");
/*GoodsDAO goodsDAO = (GoodsDAO) context.getBean("goodsDAO");
goodsDAO.save();*/
GoodsBIZ goodsBIZ = (GoodsBIZ) context.getBean("goodsBIZ");
goodsBIZ.save();
public class GoodsController {
private GoodsBIZ goodsBIZ;
public GoodsController(GoodsBIZ goodsBIZ){
System.out.println("GoodsController的有参构造被调用");
this.goodsBIZ = goodsBIZ;
}
public void save(){
System.out.println("GoodsController.save() is called...");
goodsBIZ.save();
}
}
GoodsController goodsController =
(GoodsController) context.getBean("goodsController");
goodsController.save();
<bean name="goodsController"
class="com.zpark.tea_mgr.controller.GoodsController">
<constructor-arg name="goodsBIZ" ref="goodsBIZ"/>
</bean>
public class DAOFactory {
public static GoodsDAO createDAO(){
return new GoodsDAOImpl();
}
<bean name="dao1" class="com.zpark.tea_mgr.factory.DAOFactory"
factory-method="createDAO"/>
public GoodsDAO getDAO(){
return new GoodsDAOImpl();
}
<bean name="daoFactory" class="com.zpark.tea_mgr.factory.DAOFactory"/>
<bean name="dao2" factory-bean="daoFactory" factory-method="getDAO"/>
实例的作用域
<bean name="dao1" class="com.zpark.tea_mgr.factory.DAOFactory"
factory-method="createDAO" scope="prototype"/>
scope属性默认为”singleton”,表示单例;取prototype代表多例,有些对象需要是多例的,比如Struts2中的Action就是多例的,因为他有状态(属性)
<context:annotation-config/>
<context:component-scan
base-package="com.zpark.tea_mgr.dao, com.zpark.tea_mgr.biz, com.zpark.tea_mgr.controller"/>
注解 | 作用 |
---|---|
@Controller | 控制器层 |
@Service | 业务层 |
@Repository | 数据访问层 |
@Component | 通用(通常在你不知道他是什么身份时用) |
@Scope | 默认是单例,如果是单例不要设置,要设置成多例时写为: @Scope(value=”prototype”) |
@Lazy | 默认是false, 如果不需要懒加载,不要设置,要设置成懒加载时写为: @Lazy(value=true) |
注解 | 作用 |
---|---|
@Autowired | 自动装配,by Type |
@Qualifier(“value”) | by Name ,通常作为@Autowired的补充说明,配套用 |
@Resource JSR-250规范 | 效果等价于上两者同时使用 |
@PostConstruct | 修饰的方法会在对象被初始化时调用 |
@PreDestroy | 修饰的方法会在对象被销毁时调用 |
@Configuration
@ComponentScan(value = {"com.zpark.tea_mgr.dao", "com.zpark.tea_mgr.biz"})
public class MyConfig {
}
等价于使用applicationContext.xml文件中的
<context:annotation-config/>
<context:component-scan
base-package="com.zpark.tea_mgr.dao, com.zpark.tea_mgr.biz />
ApplicationContext context =
new AnnotationConfigApplicationContext(MyConfig.class);
GoodsBIZ goodsBIZ = context.getBean(GoodsBIZ.class);
goodsBIZ.save();
Spring框架的两个核心概念: IoC 和 AOP
AOP: 面向方面(切面)编程 ,是处理实际开发中复杂业务的开发难度的
复杂的业务: 交叉的业务
一旦交叉出现,提高程序开发难度
最理想的开发状态是怎样的?分工,开发业务的人就只开发业务代码,开发事务的人仅开发事务就好
现在这个状态是开发时最理想的状态,开发业务的人只开发业务代码,开发通用功能的人只编写通用代码,这样,就达成了0耦合。但是, 开发时不存在0耦合的情况,现在,使用Spring容器工厂创建对象,创建的对象可以带有业务和通用功能。
将事务和日志这类的通用功能当成一个切面,切到我们所做的业务中,面向切面编程,就是在不影响你业务功能的基础上,附加其他的功能,在Spring工厂中实现AOP主要使用的是代理模式。
有钱人买车: 1、交钱 2、提车
中间有很多复杂的事情,可以交给代理人,由代理人帮你完成你不想做的事儿
程序猿A: 保存业务 应该做事务
程序猿A的代理: 帮A做事务,并代理保存业务
代理模式: 就是在不影响你业务功能的基础上,附加其他的功能
代理分为静态代理和动态代理
静态代理: 被代理类实际存在,代理类也实际存在
动态代理: 被代理对象和代理类都不清楚,使用反射动态生成
public class GoodsBIZ {
//保存业务和事务功能代码都要自己写
public void save(){
System.out.println("事务开始");
System.out.println("保存业务");
System.out.println("事务结束");
}
public class GoodsBIZ {
public void save(){
System.out.println("保存业务");
}
public class ProxyGoodsBIZ extends GoodsBIZ {
@Override
public void save(){
System.out.println("事务开始");
super.save();
System.out.println("事务结束");
}
public class ProxyTest {
public static void main(String[] args) {
GoodsBIZ proxyGoodsBIZ = new ProxyGoodsBIZ();
proxyGoodsBIZ.save();
}
public interface BIZ {
public void save();
}
public class GoodsBIZ implements BIZ {
@Override
public void save() {
System.out.println("保存业务");
}
public class ProxyBIZ implements BIZ {
private BIZ goodsBIZ;
public ProxyBIZ(BIZ goodsBIZ){
this.goodsBIZ = goodsBIZ;
}
@Override
public void save() {
System.out.println("事务开始");
goodsBIZ.save();
System.out.println("事务提交");
}
在代理类中有一个被代理接口的引用。这个引用将指向的是被代理对象
public class ProxyTest {
public static void main(String[] args) {
BIZ goodsBIZ = new GoodsBIZ();
BIZ proxyBIZ = new ProxyBIZ(goodsBIZ);
proxyBIZ.save();
}
@Override
public void save() {
try{
System.out.println("开始一刀");
goodsBIZ.save();
System.out.println("完成一刀");
}catch(Exception e){
e.printStackTrace();
System.out.println("异常一刀");
throw new RuntimeException(e);
}finally{
System.out.println("最终一刀");
}
}
public interface BIZ {
public void save();
}
public interface AOP {
public void before();
public void after();
public void err();
public void end();
}
public class ProxyBIZ implements BIZ{
private BIZ biz;
private AOP aop;
public ProxyBIZ(BIZ biz, AOP aop){
this.biz = biz;
this.aop = aop;
}
@Override
public void save(){
try{
aop.before();
biz.save();
aop.after();
}catch(Exception e){
e.printStackTrace();
aop.err();
throw new RuntimeException(e);
}finally{
aop.end();
}
public class GoodsBIZ implements BIZ {
@Override
public void save() {
System.out.println("保存业务");
System.out.println(5/0);
}
public class TranAOP implements AOP {
@Override
public void before() {
System.out.println("事务开始");
}
@Override
public void after() {
System.out.println("事务提交");
}
@Override
public void err() {
System.out.println("事务回滚");
}
@Override
public void end() {
System.out.println("事务结束");
}
public class ProxyTest {
public static void main(String[] args) {
BIZ goodsBIZ = new GoodsBIZ();
AOP tranAOP = new TranAOP();
ProxyBIZ proxyBIZ = new ProxyBIZ(goodsBIZ, tranAOP);
proxyBIZ.save();
}
动态代理: 可以反射不针对具体的方法进行代理的代理类
这个动态代理类是根据反射的代码动态生成的,这个类我们看不到
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
newProxyInstance方法返回的就是一个代理类的实例。 代理类是在这个方法执行过程中动态创建的,我们看不到
ClassLoader: 类加载器,代理类是动态创建的,执行前没有这个类,他使用被代理对象的类加载器 Class<?>[] interfaces: 被代理的接口数组,基于JDK的动态代理只能针对接口 InvocationHandler h: 回调函数 回调函数就是动态生成的代理类要执行的源代码,它invoke方法里面的内容由我们编写
这个接口代表了动态代理类的行为
在这个接口中只有一个方法: invoke
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
Object proxy: 动态代理的对象 Method method: 当前代理的方法对象 Object[] args: 当前代理的方法的参数
在开发时,这个接口的实现类要程序员自己编写,编写的内容就是动态代理的代理内容
public class ProxyHandler implements InvocationHandler {
private Object obj;
private AOP aop;
public ProxyHandler(Object obj, AOP aop){
this.obj = obj;
this.aop = aop;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
try{
aop.before();
Object proxyObj = method.invoke(obj, args);
aop.after();
return proxyObj;
}catch(Exception e){
e.printStackTrace();
aop.err();
throw new RuntimeException(e);
}finally{
aop.end();
}
}
}
public class ProxyFactory {
public static Object createProxyObjcet(Object obj, AOP aop){
return Proxy.newProxyInstance(
obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),
new ProxyHandler(obj, aop));
}
}
BIZ goodsBIZ = new GoodsBIZ();
AOP tranAOP = new TranAOP();
BIZ proxyBIZ = (BIZ) ProxyFactory.createProxyObjcet(goodsBIZ, tranAOP);
proxyBIZ.save();
评论