Spring简介

Spring

Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。
Spring中主要包含六大框架:在这里插入图片描述

  • Spring DAO:提供对JDBC的操作支持:JDBCTemplate模板工具类;
  • Spring ORM:整合Hibernate等ORM(对象关系映射Object Relational Mapping)框架;
    ORM 封装包提供了常用的“对象/关系”映射APIs的集成层。 其中包括JPA、JDO、Hibernate 和 iBatis 。利用ORM封装包,可以混合使用所有Spring提供的特性进行**“对象/关系”映射**
  • Spring Web:提供了对Struts、SpringMVC的支持,支持Web开发。Spring自身也提供了基于MVC的解决方案;
  • Spring AOP:Spring提供了 面向切面的编程,可以定义方法拦截器(method-interceptors)和切点(pointcuts)
  • Spring JEE:J2EE开发规范的支持,例如EJB
  • Spring Core:提供IOC容器对象的创建和处理依赖对象关系 ,实际就是BeanFactory。

还有一个Spring Context:
构建于Core封装包基础上的 Context封装包,提供了一种框架式的对象访问方法,有些象JNDI注册器。Context封装包的特性得自于Beans封装包,并添加了对国际化(I18N)的支持(例如资源绑定),事件传播,资源装载的方式和Context的透明创建,比如说通过Servlet容器。

在这里插入图片描述

IOC容器和DI Dependency Injection

控制反转:new一个实例的控制权不交给程序员来做而是交给Spring容器来做。

IOC容器:可以创建对象的容器,负责实例化、定位、配置应用程序中的对象以及建立这些对象之间的依赖,具有依赖注入功能。
Spring中的BeanFactory就是IOC容器的实际代表者。
在这里插入图片描述
DI依赖注入:在容器创建对象之后,处理对象的依赖关系。

依赖注入的几种方式:

  1. set注入
  2. 静态工厂注入
  3. 构造方法注入
  4. 基于注解的方式
set注入

在OrderAction中声明一个 OrderServiceImpl类的对象 orderService,并实现setter方法。

Spring配置XML文件:其中配置声明OrderAction类存在属性orderService。
程式运行时候,会将已经实例化的orderService对象调用setOrderService方式注入。

<bean name="orderAction" class="com.pec.action.OrderAction">
        <property name="orderService" ref="orderService"></property>
</bean>
<bean name="orderService" class="com.pec.service.imp.OrderServiceImp"></bean>
构造器注入

在OrderAction的构造函数中将OrderServiceImpl的实例对象作为参数传递进来。

Spring配置XML文件:

<bean name="orderAction" class="com.pec.action.OrderAction">
      <constructor-arg ref="orderService"></constructor-arg>
</bean>
<bean name="orderService" class="com.pec.service.imp.OrderServiceImp"></bean>
静态工厂注入
静态工厂方法

1.一个Car类,写上get set方法,重写ToString方法
2.静态工厂类
public class StaticCarFactory {

	private static Map<String, Car> cars = new HashMap<>();

	static {
		cars.put("audi", new Car("audi", "300000"));
		cars.put("bens", new Car("bens", "400000"));
	}

	public static Car getCar(String name) {
		return cars.get(name);
	}

}

xml文件:

<bean id="car1" class="com.lzj.spring.beans.factory.StaticFactory"
        factory-method="getCar">
        <constructor-arg value="bens"></constructor-arg>
    </bean>
实例化静态工厂注入Bean

实例化静态工厂注入bean,需要先实例化一个工厂类,然后通过由实例化工厂对象中的一个静态方法来创建bean,并注入到容器中。

<!--首先创建一个工厂的bean-->
    <bean id="carFactory" class="com.lzj.spring.beans.factory.InstanceFactory"></bean>
    <!--factory-bean指定前面已经创建的bean; factory-method指定工厂实例中用于创建car的方法; constructor-arg指定创建car方法中传入的参数-->
    <bean id="car2" factory-bean="carFactory" factory-method="getCar">
        <constructor-arg value="baoma"></constructor-arg>
    </bean>

测试类:

public class Main {

	public static void main(String[] args) {

		ApplicationContext apx = new ClassPathXmlApplicationContext("bean-factory.xml");

		Car car1 = (Car) apx.getBean("car1");
		System.out.println(car1);

	}
}
基于注解方式注入

这个比较常用,就是使用@Autowired将Service层的对象注入(当然,Service层还需要用@Service(“这个名字要和Controller层注入的service对象名称一致”))

同理 DAO层也需要用@Repository(“xXXXDao”)注解
在这里插入图片描述

@Scope定义bean的作用域,其默认作用域是”singleton”,除此之外还有prototype,request,session和global session。
@Value:@Value里面的内容一定是资源文件里面的key值

@Resource和@Autowired的区别:
详见《Spring中@Autowired和@Resource的区别》

Spring 中的AOP是OOP的延续,通过预编译和运行期间动态代理实现程序功能统一维护的一种技术。
AOP采用横向抽取机制,取代了传统纵向继承体系重复性代码,对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高了程序的可重用性,提高开发效率。

AOP的经典应用:事务管理、性能监视、安全检查、缓存、日志
AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入。
使用AspectJ注入式切面和@AspectJ注解驱动的切面实际上底层也是通过动态代理实现的。

实现AOP的技术,主要分为两大类:
一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;

二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。

AOP涉及名称:

切面(Aspect):其实就是共有功能的实现,是一个类。如日志切面、权限切面、事务切面等。在实际应用中通常是一个存放共有功能实现的普通Java类,之所以能被AOP容器识别成切面,是在配置中指定的。

通知(Advice):是切面的具体实现(是一个方法)。
以目标方法为参照点,根据放置的地方不同,可分为前置通知(Before)、后置通知(AfterReturning)、异常通知(AfterThrowing)、最终通知(After)与环绕通知(Around)5种。
在实际应用中通常是切面类中的一个方法,具体属于哪类通知,同样是在配置中指定的。

**目标对象(Target):就是那些即将切入切面的对象,也就是那些被通知的对象。**这些对象中已经只剩下干干净净的核心业务逻辑代码了,所有的共有功能代码等待AOP容器的切入。

代理对象(Proxy):将通知应用到目标对象之后被动态创建的对象。可以简单地理解为,代理对象的功能等于目标对象的核心业务逻辑功能加上共有功能。代理对象对于使用者而言是透明的,是程序运行过程中的产物。

织入(Weaving):将切面应用到目标对象从而创建一个新的代理对象的过程。这个过程可以发生在编译期、类装载期及运行期,当然不同的发生点有着不同的前提条件。
譬如发生在编译期的话,就要求有一个支持这种AOP实现的特殊编译器;发生在类装载期,就要求有一个支持AOP实现的特殊类装载器;只有发生在运行期,则可直接通过Java语言的反射机制与动态代理机制来动态实现。

连接点(Joinpoint):就是程序在运行过程中能够插入切面的地点。例如,方法调用、异常抛出或字段修改等,但Spring只支持方法级的连接点

切入点(Pointcut):用于定义通知应该切入到哪些连接点上。不同的通知通常需要切入到不同的连接点上,这种精准的匹配是由切入点的正则表达式来定义的。
在这里插入图片描述

Spring实现AOP:JDK动态代理和CGLIB代理

JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理;其核心的两个类是InvocationHandler和Proxy
详见《java中的代理(静态代理和动态代理)》

CGLIB代理:实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类
CGLIB(Code Generation Library)是高效的代码生成包,底层是依靠ASM(开源的java字节码编辑类库)操作字节码实现的,性能比JDK强;简单来说,就是运行时动态生成字节码文件。
需要引入包asm.jar和cglib.jar。

CGLib采用非常底层的字节码技术,就可以为一个类创建一个子类,并在 子类中采用方法拦截的技术拦截所有的父类方法的调用,并顺势织入横切逻辑。
CGLib和jdk的原理类似,也是要通过方法去反射调用目标对象的方法。
详见下面的例子:

//目标对象RealSubject,cglib不需要定义目标类的统一接口
public class RealSubject {
    public void request() {
        System.out.println("real subject execute request");
    }
    public void hello() {
        System.out.println("hello");
    }
}

代理对象:

//实现MethodInterceptor,定义实现方法的拦截器
 public class DemoMethodInterceptor implements MethodInterceptor{
     //参数分别为:1、代理对象;2、委托类方法;3、方法参数;4、代理方法的MethodProxy对象。
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
               // 被织入的横切内容,开始时间 before
             long start = System.currentTimeMillis();
            System.out.println("before in cglib");
            Object result = null;
            try{
            //调用父类方法
                result = proxy.invokeSuper(obj, args);
            }catch (Exception e){
                System.out.println("get ex:"+e.getMessage());
                throw e;
            }finally {
             // 被织入的横切内容,结束时间
     	   		Long span = System.currentTimeMillis() - start;
    		   System.out.println("共用时:" + span);  
                System.out.println("after in cglib");
            }
            return result;
        }
    }

客户端实现调用:

//客户端
public class Client {
    public static void main(String[] args){
    //增强器,动态代码生成器
        Enhancer enhancer = new Enhancer();
        //设置父类类型
        enhancer.setSuperclass(RealSubject.class);
        //回调函数
        enhancer.setCallback(new DemoMethodInterceptor());
        //动态生成字节码并返回代理对象
        // 此刻,realSubject不是单纯的目标类,而是增强过的目标类  
        RealSubject realSubject = (RealSubject) enhancer.create();
        //调用目标类的方法
        realSubject.hello();
        realSubject.request()
    }
}

代理对象的生成过程由Enhancer类实现,大概步骤如下:
1、生成代理类Class的二进制字节码;
2、通过Class.forName加载二进制字节码,生成Class对象;
3、通过反射机制获取实例构造,并初始化代理类对象。

若目标对象实现了接口,spring默认使用JDK的动态代理。
若目标对象没有实现任何接口,spring使用CGLIB进行动态代理。

使用JDK方式的耦合性更高。
强制使用 CGLIB:

@SpringBootApplication
//强制使用cglib代理
@EnableAspectJAutoProxy(proxyTargetClass = tree)
public class AopDemoApplication{
    public static void main(String[] args){
        SpringApplication.run(AopDemoApplication.class,args);
    }
    }

详细理论请看:http://www.cnblogs.com/xiaoxing/p/5836835.html
动态代理详细实现请看:http://www.cnblogs.com/best/p/5679656.html#_label3

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值