Spring(快速入门到原理分析)

一:概述

1.1:Spring是做什么?

为JavaEE各层提供了解决方案

二:IOC

2.1:IOC(控制反转)概述

a:定义:将对象的创建交给工厂。包括依赖注入和依赖查找。
b:实现:工厂+配置文件

2.2:工厂类层级图

在这里插入图片描述

2.3:BeanFactory和ApplicationContext区别

ApplicationContext:只要一读取配置文件,默认情况下就会创建对象。
BeanFactory:什么时候使用什么时候创建对象。

2.4:bean标签

<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>

	id:对象在容器唯一标识,用于获取对象。
	class:类的全类名。用反射创建对象,调用无参构造方法。
	scope:指定对象的作用范围(重点)
		* singleton :默认值,单例的.
		* prototype :多例的.
		* request :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中.
		* session :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中.
		* global session :WEB 项目中,应用在 Portlet 环境.如果没有 Portlet 环境,那么globalSession 相当于 session.
	init-method:指定类中的初始化方法名称。
	destroy-method:指定类中销毁方法名称

2.4:对象作用范围对应的生命周期

  1. singleton:一个应用只有一个对象实例
生命周期:
	对象出生:当应用加载,创建容器时,对象就被创建了。
	对象活着:只要容器在,对象一直活着。
	对象死亡:当应用卸载,销毁容器时,对象就被销毁了。
  1. prototype:每次访问都会创建新对象实例
生命周期:
	对象出生:当使用对象时,创建新的对象实例。
	对象活着:只要对象在使用中,就一直活着。
	对象死亡:当对象长时间不用时,被 java 的垃圾回收器回收了。

2.5:依赖注入

  1. 构造函数依赖注入(基本类型、字符串、对象)
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"> 
	<constructor-arg name="name" value="张三"></constructor-arg> 
	<constructor-arg name="age" value="18"></constructor-arg> 
	<constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>
<bean id="now" class="java.util.Date"></bean>

constructor-arg:标签
	===给谁赋值====
	name:构造函数参数名称。
	=====赋什么值======
	value:基本数据类型和String
	ref:是bean对象
  1. set方法注入(基本类型、字符串、对象)
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"> 
	<property name="name" value="test"></property> 
	<property name="age" value="21"></property>
	<property name="birthday" ref="now"></property>
</bean> 
<bean id="now" class="java.util.Date"></bean>

property:标签
	属性:
	name:找的是类中 set 方法后面的部分
	ref:给属性赋值是其他 bean 类型的
	value:给属性赋值是基本数据类型和 string 类型的

2.6:注解配置

2.6.1:@Component、@Controller 、@Service、 @Repository

a:value:指定bean的id
b:写在类上,相当于在 xml 中配置一个 bean。

2.6.2:依赖注入

  1. @Autowired
是能用于注入bean类型,根据bean类型进行匹配,匹配不到会报错。当含有多个该类型对象需要根据bean的id进行配置(@Qualifier)。
  1. @Resource
只能按照bean的id进行注入。
  1. @Value
注入基本类型和String.
  1. @Configuration
用于指定当前类是一个 spring 配置类,当创建容器时会从该类上加载注解。
  1. @ComponentScan
用于指定 spring 在初始化容器时要扫描的包。(扫描注解)

@Configuration
@ComponentScan("com.itheima")
public class SpringConfiguration {
}
  1. @Bean
该注解只能写在方法上,表明使用此方法创建一个对象,并且放入 spring 容器。
name:代表对象名称。
  1. @PropertySource
配置文件加载

@Configuration
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig {
	@Value("${jdbc.driver}")
	private String driver;
	@Value("${jdbc.url}")
	private String url;
	@Value("${jdbc.username}")
	private String username;
	@Value("${jdbc.password}")
	private String password;
	/**
	* 创建一个数据源,并存入 spring 容器中
	* @return
	*/
	@Bean(name="dataSource")
	public DataSource createDataSource() {
		try {
			ComboPooledDataSource ds = new ComboPooledDataSource();
			ds.setDriverClass(driver);
			ds.setJdbcUrl(url);
			ds.setUser(username);
			ds.setPassword(password);
			return ds;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
 }
  1. @Import
用于导入其他配置类。

@Configuration
@ComponentScan(basePackages = "com.itheima.spring") 
@Import({ JdbcConfig.class})
public class SpringConfiguration { 
}

@Configuration
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig{
}

三:动态代理

3.1: 概述

字节码随用随创建,随用随加载。

3.2: JDK动态代理

  1. 接口(实例)
/**
 * 一个经纪公司的要求:能做基本的表演和危险的表演
 */
public interface IActor {
    /**
     * 基本演出
     */
    public void basicAct(float money);
    /**
     * 危险演出
     */
    public void dangerAct(float money);
}
  1. 实现类(实例)
JDK官方的Proxy,被代理类必须至少实现一个接口。

/**
 * 一个演员
 */
public class Actor implements IActor{
    public void basicAct(float money){
        System.out.println("拿到钱,开始基本的表演:"+money);
    }
    public void dangerAct(float money){
        System.out.println("拿到钱,开始危险的表演:"+money);
    }
}
  1. 动态代理是实现(实例)
public class Client {
	public static void main(String[] args) {
	    //一个剧组找演员:
	    final Actor actor = new Actor();//直接
	
		 /**
		  * 创建的方式
		     * Proxy.newProxyInstance(三个参数)
		  * 参数含义:
		  * ClassLoader:和被代理对象使用相同的类加载器。
		  * Interfaces:和被代理对象具有相同的行为。实现相同的接口。
		  * InvocationHandler:如何代理。
		      * 策略模式:使用场景是:
		      * 数据有了,目的明确。
		      * 如何达成目标,就是策略。
		  */
	    IActor proxyActor = (IActor) Proxy.newProxyInstance(
           actor.getClass().getClassLoader(),
           actor.getClass().getInterfaces(),
           new InvocationHandler() {
			 /**
		     * 此方法有拦截的功能,执行被代理对象的任何方法,都会经过该方法。
		     * 参数:
		         * proxy:代理对象的引用。不一定每次都用得到
		         * method:当前执行的方法对象
		         * args:执行方法所需的参数
		     * 返回值:
		        * 当前执行方法的返回值
		     */
               @Override
               public Object invoke(Object proxy, 
				               	Method method, 
				                Object[] args) throws Throwable {
                   String name = method.getName();
                   Float money = (Float) args[0];
                   Object rtValue = null;
                   //每个经纪公司对不同演出收费不一样,此处开始判断
                   if("basicAct".equals(name)){
                       //基本演出,没有 2000 不演
                       if(money > 2000){
                           //看上去剧组是给了 8000,实际到演员手里只有 4000
                           //这就是我们没有修改原来 basicAct 方法源码,对方法进行了增强
                           rtValue = method.invoke(actor, money/2);
                       } }
                   if("dangerAct".equals(name)){
                       //危险演出,没有 5000 不演
                       if(money > 5000){
                           //看上去剧组是给了 50000,实际到演员手里只有 25000
                           //这就是我们没有修改原来 dangerAct 方法源码,对方法进行了增强
                           rtValue = method.invoke(actor, money/2);
                       } }
                   return rtValue;
               }
           });
	    //没有经纪公司的时候,直接找演员。
	    // actor.basicAct(1000f);
	    // actor.dangerAct(5000f);
	    //剧组无法直接联系演员,而是由经纪公司找的演员
	    proxyActor.basicAct(8000f);
	    proxyActor.dangerAct(50000f);
	} 
}

3.3:CGLib动态代理

 /**
 * 一个演员
  */
 public class Actor{//没有实现任何接口
     public void basicAct(float money){
         System.out.println("拿到钱,开始基本的表演:"+money);
     }
     public void dangerAct(float money){
         System.out.println("拿到钱,开始危险的表演:"+money);
     } 
 }
  1. 动态代理实现
public class Client {
 public static void main(String[] args) {
      final Actor actor = new Actor();
      /**
       * 要求:
          * 被代理对象不能是最终类
       * 用到的类:
          * Enhancer
       * 用到的方法:
          * create(Class, Callback)
       * 方法的参数:
          * Class:被代理对象的字节码
          * Callback:如何代理
       */
      Actor cglibActor = (Actor) Enhancer.create(actor.getClass(),new MethodInterceptor() {
             /**
              * 此方法具有拦截作用,执行被代理对象的任何方法,都会经过该方法。
              * 参数:
                 * 前三个和基于接口的动态代理是一样的。
                 * MethodProxy:当前执行方法的代理对象。
              * 返回值:
                 * 当前执行方法的返回值
              */
             @Override
             public Object intercept(Object proxy, Method method, Object[] args,
                                     MethodProxy methodProxy) throws Throwable {
                 String name = method.getName();
                 Float money = (Float) args[0];
                 Object rtValue = null;
                 if("basicAct".equals(name)){
                     //基本演出
                     if(money > 2000){
                         rtValue = method.invoke(actor, money/2);
                     } }
                 if("dangerAct".equals(name)){
                     //危险演出
                     if(money > 5000){
                         rtValue = method.invoke(actor, money/2);
                     } }
                 return rtValue;
             }
         });
      cglibActor.basicAct(10000);
      cglibActor.dangerAct(100000);
  } 
}

三:AOP(面向切面编程)

3.1:AOP概述

a:把我们重复性代码抽取出来。在不修改源码的基础上,对我们已有的方法增强。
b:使用技术:动态代理技术。

3.2:Spring中AOP实现细节

3.2.1: 术语

Joinpoint(连接点):
    所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的
    连接点。
Pointcut(切入点):
    所谓切入点是指我们要对哪些 Joinpoint进行拦截的定义。
Advice(通知/增强):
    所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。
    通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
Introduction(引介):
    引介是一种特殊的通知在不修改类代码的前提下,Introduction可以在运行期为类动态地添加一些方
    法或Field。
Target(目标对象):
    代理的目标对象。
Weaving(织入):
    是指把增强应用到目标对象来创建新的代理对象的过程。
    spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。
Proxy(代理):
    一个类被 AOP 织入增强后,就产生一个结果代理类。
Aspect(切面):
    是切入点和通知(引介)的结合。

3.2.2:Spring的AOP案例

  1. 配置
<!-- 配置切入点 --> 
<aop:config> 
	<aop:pointcut expression="execution(* com.itheima.service.impl.*.*(..))" id="pt1"/>
	<!-- 配置切面 --> 
	<aop:aspect id="txAdvice" ref="txManager">
		<!-- 配置环绕通知 --> 
		<aop:around method="transactionAround" pointcut-ref="pt1"/>
	</aop:aspect>
</aop:config>
  1. 实现类
/**
* 环绕通知
 * spring 框架为我们提供了一个接口:ProceedingJoinPoint,它可以作为环绕通知的方法参数。
 * 在环绕通知执行时,spring 框架会为我们提供该接口的实现类对象,我们直接使用就行。
 */
public Object transactionAround(ProceedingJoinPoint pjp) {
    //定义返回值
    Object rtValue = null;
    try {
        //获取方法执行所需的参数
        Object[] args = pjp.getArgs();
        //前置通知:开启事务
        beginTransaction();
        //执行方法
        rtValue = pjp.proceed(args);
        //后置通知:提交事务
        commit();
    }catch(Throwable e) {
        //异常通知:回滚事务
        rollback();
        e.printStackTrace();
    }finally {
        //最终通知:释放资源
        release();
    }
    return rtValue; 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值