Spring简单理解

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;
        }
    }
    
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值