Spring 教程(一)

 Spring 基本概述

1.1 Spring是什么

spring框架是于2003年兴起的一个轻量级的java开发框架,有Rod Johnson创建,是针对bean的生命周期进行管理的轻量级容器,使现有的技术更加容易使用,简单来说Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架 !

1.2 Spring的优点

1)方便解耦,简化开发

通过Spring提供的IOC容器,可以将对象间的依赖关系交友Spring进行控制,避免硬编码所造成的过度耦合。

2)AOP编程的支持

通过Spring的AOP功能,方便进行面向切面编程,许多不容易用传统OOP实现的功能可以通过AOP轻松实现。

3)声明式事务的支持

可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务管理,提高开发效率和质量。

4)方便程序的测试

可以使用非容器依赖的编程方式进行几乎所有的测试工作,测试不在是昂贵的操做,而是随手可做的事情。

5)方便集成各种优秀框架

Spring对各种优秀框架(Struts,Hibernate,Hessian,Quartz等)的支持

6)降低javaaEE API的使用难度

Spring对javaEE API (如jdbc,javaMail,远程调用等) 进行了薄薄的封装,使这些API的使用难度大大降低

1.3 组成

什么是IOC

1. IOC本质

控制反转,是一种设计思想,DI(依赖注入) 是实现IOC的一种方法,通过描述(xml或者注解)并通过第三方去生产或获取特定对象的方法,在spring中实现控制反转的是IOC容器,其实现方法是依赖注入

2.xml方式开发

2.1 传统应用程序的队友是由程序本身控制创建,在哪里使用就在哪里new 对象

Users users = new Users(); //无参构造,通过set注入属性值
users.setUserId(1L);
users.setUserName("张三");
users.setUserPwd("123456");
Users users1 = new Users(1L,"张三","123456"); //全参构造
System.out.println(users.toString());// Users: userId=1,userName:张三,userPwd:123456;
System.out.println(users1.toString());// Users: userId=1,userName:张三,userPwd:123456;

2.2 Spring 创建bean

1)首先创建一个maven工程,在pom.xml文件中导入Spring的依赖

<!--测试-->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.2.9.RELEASE</version>
</dependency>
<!--spring核心包-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.9.RELEASE</version>
</dependency>

2) 在resources包下创建applicationContext.xml配置文件,是Spring配置文件约定俗成的名字

 3)在applicationContext.xml配置Users,这个时候bean没有被创建,当调用getBean()方法时才会实例化bean

4)bean的依赖注入,在applicationContext.xml通过构造函数,和set注入

数组,集合等数据类型,没写,请百度

<?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">

    <!--这里就配置了Users的实例方法,等同于new Users(); -->
    <bean id="users" class="cn.zb.spring.entity.Users" scope="singleton">
        <!--默认使无参构造,下面使用有参构造,根据参数名,进行赋值-->
        <!--<constructor-arg index="0" value="1"/> 根据参数下标进行赋值-->
        <constructor-arg name="userId" value="1"/>
        <constructor-arg name="userName" value="张三"/>
        <constructor-arg name="userPwd" value="123"/>
        <!--使用set注入属性值-->
        <!--基本数据类型-->
        <property name="userId" value="1"/>
    </bean>
</beans>

spring提供IOC容器实现两种方式

BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供给开发任意使用

ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员使用

测试,通过applicationContext.xml配置文件获得User实例对象

ApplicationContext context=new ClassPathXmlApplicationContext("application.xml");
Users users = context.getBean("users", Users.class);
System.out.println(users.toString()); //Users: userId=1,userName:张三,userPwd:123;

5)bean的作用域

 6)bean的自动装配

ByName:会自动在容器上下文中查找,和自己对象方法set对象后面的值对应的bean id,需要保证所有bean的id唯一

ByType:会自动在容器上下文中查找,和自己对象属性类型相同的bean,需要保证所有bean的class唯一

3.注解方式开发

3.1Spring原始注解

spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发时一种趋势,注解代替xml配置,提高开发效率

 3.2 Spring新注解

使用新注解就是为了实现用注册代替原始注解不能表示的内容,全面替代之前的核心配置文件applicationContext.xml,使用核心配置类来进行配置,SpringConfiguration是核心配置类

package cn.zb.spring;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("cn.zb.spring")
public class SpringConfiguration {
}

UserService是接口,包含show()方法;

package cn.zb.spring.service.impl;

import cn.zb.spring.entity.Users;
import cn.zb.spring.service.UserService;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

//<bean id="userServiceImpl" class="cn.zb.spring.service.impl.UserServiceImpl">
//@Component("userServiceImpl")
//@Scope("singleton")
@Service
public class UserServiceImpl implements UserService {
    @Override
    public void show(Users users) {
        System.out.println(users.toString());
    }

    @PostConstruct
    @Override
    public void init() {
        System.out.println("初始化方法"); //在初始化以前执行
    }

    @PreDestroy
    @Override
    public void destroy() {
        System.out.println("销毁方法"); //在容器销毁前执行,但是要改成手动关闭容器才行
    }
}

3.3 Spring集成Junit测试

1)编写测试类

package cn.zb.test;


import cn.zb.spring.SpringConfiguration;
import cn.zb.spring.entity.Users;
import cn.zb.spring.service.UserService;
import cn.zb.spring.service.impl.UserServiceImpl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

@RunWith(SpringJUnit4ClassRunner.class) //替换原来的运行期
@ContextConfiguration(classes = {SpringConfiguration.class}) //指定配置文件或配置类
public class SpringJunitTest {

    @Autowired //注入对象
    //@Qualifier("userServiceImpl")
    //@Resource
    private UserServiceImpl userService;

    @Test
    public void test(){
        //Users users=new Users();
        ApplicationContext context=new ClassPathXmlApplicationContext("application.xml");
        Users users = context.getBean("users", Users.class);
        userService.show(users); //Users: userId=1,userName:张三,userPwd:123;
    }

}

什么是AOP

1.AOP简介

AOP 是面向切面 Aspect-oriented programming(方法)的编程的简写,AOP的实现可以把业务逻辑和系统级的服务进行隔离,是业务逻辑与各个系统级服务的耦合度降低,从而提高程序的重用性和开发效率,AOP的底层实现原理是动态代理。

下面的案例是基于JDK动态代理,JDK动态代理机制只能代理实现了接口的类

package cn.zb.spring.dao;

import cn.zb.spring.service.UserService;
import cn.zb.spring.service.impl.UserServiceImpl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class UserDao {
    private UserServiceImpl userServiceImpl=new UserServiceImpl();

    /**
     * getClassLoader() : 类加载器,用于加载代理类,使用真实对象的类加载器
     * getInterfaces() : 真是对象所实习的接口,代理模式真实对象和代理对象实现相同的接口
     * InvocationHandler() : 代理对象的调用处理程序
     */
    public UserService getProxyObject(){
        UserService userService=(UserService) Proxy.newProxyInstance(
                userServiceImpl.getClass().getClassLoader(),
                userServiceImpl.getClass().getInterfaces(),
                new InvocationHandler() {
                    /**
                     * proxy : 代理对象
                     * method : 对应于在代理对象上调用的接口方法的Method实例
                     * args : 代理对象调用接口方法是传递的实际参数
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object result = method.invoke(userServiceImpl, args);
                        return result;
                    }
                }
        );
        return userService;
    }
}
@Test
public void test3(){
    Users users = new Users(1L,"张三","123456");
    UserDao userDao=new UserDao();
    UserService proxyObject = userDao.getProxyObject();
    proxyObject.show(users); //Users: userId=1,userName:张三,userPwd:123456;
}

2.什么是AspectJ

对于AOP的这种编程思想,由很多框架或者组件进行了实现,Spring实现AOP就是其中一种,AspectJ也实现了AOP而且实现方式更为简单,使用起来更为方便,所以Spring将AspectJ对于AOP的实现引入了自己的框架中。

2.1 AOP的几个术语

 

1)横切关注点

跨越应用程序多个模块的方法或功能,就是与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点,如日志,安全,缓存,事务等待

2)连接点

连接点是在应用执行中能够切入切面的一个点,即程序执行过程中能购应用通知的所有点

3)切点

切点是真正需要插入切面的一个或多个连接点,即通知被应用的具体位置,通常使用明确的类和方法名称,或是利用正则表达式定义所匹配的类和方法名称来指定这些点(比如Aspect切点表达式)

4)通知

切面的工作被成为通知。即包含了需要多个应用对象的横切行为

AspectJ的通知类型

@Before 前置通知

@Around 环绕通知

@AfterReturning 后置通知

@AfterThrowing 异常通知

@After 最终通知,不管是否异常,该通知都会执行

5)切面

切面式通知和切点的结合,通知和切点共同定义了切面的全部内容

6)织入

织入式把切面应用到目标对象并创建新的代理对象的过程,切面在指定的连接到被织入到目标对象中,在目标对象的生命周期里有多个点可以进行织入(编译期,类加载期,运行期)

7)引入

引入指定的是现有的类添加新方法或属性

2.2 Spring配置AspectJ

1)引入依赖

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.6</version>
</dependency>

2)使用xml方式配置

<bean id="userServiceImplProxy" class="cn.zb.spring.service.impl.UserServiceImplProxy"/>
<!--配置aop增强-->
<aop:config>
    <!--切入点-->
    <aop:pointcut id="p" expression="execution(* cn.zb.spring.service.impl.UserServiceImpl.show(..))"/>
    <!--配置切面-->
    <aop:aspect ref="userServiceImplProxy">
        <!--增强方法作用在具体方法上-->
        <aop:before method="beforeAdvice" pointcut-ref="p"/>
    </aop:aspect>
</aop:config>

3)使用注解@Aspect创建切面

方法切入语法:

execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)

package cn.zb.spring.service.impl;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class UserServiceImplProxy {

    //相同切入点提取
    @Pointcut(value ="execution(* cn.zb.spring.service.impl.UserServiceImpl.show(..))")
    public void executions(){};

    @Before(value = "executions()")
    public void beforeAdvice(){
        System.out.println("前置通知");
    }

    @After(value = "executions()")
    public void afterAdvice(){
        System.out.println("最终通知");
    }

    @Around(value = "executions()")
    public void aroundAdvice(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("环绕通知,在方法运行前执行");
        pjp.proceed();
        System.out.println("环绕通知,在方法运行后执行");
    }
    
    @AfterReturning(value = "executions()")
    public void afterReturningAdvice(){
        System.out.println("后置通知");
    }

    @AfterThrowing(value = "executions()")
    public void afterThrowingAdvice(){
        System.out.println("异常通知");
    }

}

4)启用自动代理

在SpringConfiguration配置类添加注解@EnableAspectJAutoProxy

5)测试类运行,查看结果

 本文做记录使用,参考了其他的文献

Spring集成数据库,mybatis在后面的Spring 教程(二)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值