Spring学习笔记

IoC和DI理解

https://www.w3cschool.cn/wkspring/tydj1ick.html spring在线文档

IoC(控制反转)

  首先想说说IoC(Inversion of Control,控制反转)。这是spring的核心,贯穿始终。所谓IoC,对于spring框架来说,
就是由spring来负责控制对象的生命周期和对象间的关系。这是什么意思呢,举个简单的例子,我们是如何找女朋友的?常
见的情况是,我们到处去看哪里有长得漂亮身材又好的mm,然后打听她们的兴趣爱好、qq号、电话号、ip号、iq号………
,想办法认识她们,投其所好送其所要,然后嘿嘿……这个过程是复杂深奥的,我们必须自己设计和面对每个环节。传统的程序
开发也是如此,在一个对象中,如果要使用另外的对象,就必须得到它(自己new一个,或者从JNDI中查询一个),
使用完之后还要将对象销毁(比如Connection等),对象始终会和其他的接口或类藕合起来。

  那么IoC是如何做的呢?有点像通过婚介找女朋友,在我和女朋友之间引入了一个第三者:婚姻介绍所。婚介管理了很多男
男女女的资料,我可以向婚介提出一个列表,告诉它我想找个什么样的女朋友,比如长得像李嘉欣,身材像林熙雷,唱歌像周
杰伦,速度像卡洛斯,技术像齐达内之类的,然后婚介就会按照我们的要求,提供一个mm,我们只需要去和她谈恋爱、结婚
就行了。简单明了,如果婚介给我们的人选不符合要求,我们就会抛出异常。整个过程不再由我自己控制,而是有婚介这样一
个类似容器的机构来控制。Spring所倡导的开发方式就是如此,所有的类都会在spring容器中登记,告诉spring你是个什么东
西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。
所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体
的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。

DI(依赖注入)

  IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Inje
ction,依赖注入)来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection
对象,有了 spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,
A不需要知道。在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就
完成了对各个对象之间关系的控制。A需要依赖 Connection才能正常运行,而这个Connection是由spring注入到A中的
,依赖注入的名字就这么来的。那么DI是如何实现的呢? Java 1.3之后一个重要特征是反射(reflection),它允许程序
在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入的。

理解了IoC和DI的概念后,一切都将变得简单明了,剩下的工作只是在spring的框架中堆积木而已。


装配bean基于xml

实例化方式

<bean id="beans1" class="helloImpl"/>

<bean>配置需要创建的对象
id:用于之后从spring容器获得实例时使用的
class:需要创建实例的全限定类名

 @Test
    public void test1(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        helloImpl beans1 = (helloImpl) context.getBean("beans1");
        beans1.say();
    }
  

BeanFactor: 这是一个工厂,用于生成任意bean,采取延迟加载,第一次getBean时才会初始化Bean

ApplicationContext:是BeanFactor的子接口,功能更强大(国际化处理,事件传递,bean自动装配,各种不同应用层的context
实现)。当配置文件被加载,就进行对象实例化

ClassPathXmlApplicationContext:用于加载classpath(类路径,src)下的xml
加载xml运行位置-》WEB-INF/class/。。。xml

FileSystemXmlApplicationContext:用于加载指定盘符下的xml
加载xml运行位置-》WEB-INF/。。。xml
通过javaweb ServletContext getRealPath()获得具体盘符

静态工厂创建的实例交予spring
class:确定静态工厂全限定类名
factory-method:确定静态方法

工厂:
public class mybeanfactory{
	public static userservice createservice(){
		return new userserviceimpl();
	}
}


spring配置
	将静态工厂创建的实例交予spring
		class确定静态工厂全限定类名
		factory-method 确定静态方法名

    
 静态工厂(方法静态),测试的时候  不需要new工厂  可以直接工厂.方法
	userservice s=mybeanfactory.createservice();
	s.adduser();
 配置静态工厂的spring xml
	<bean id=""  class="(工厂的全限定类名)" factory-method="(方法名(可能有很多就写清楚具体方法))"</bean>
 
 实例工厂:需要new
 	mybeanfactory  f= new mybeanfactory();
	userservice s=f.createservice();
	s.adduser();

 配置实例工厂的spring xml
	1.创建工厂实例
		<bean id="a"  class=""/>
	2.获取userservice  factory-bean 确定工厂实例  factory-method 确定普通方法
		<bean id=""  factory-bean="a"  factory-method="(工厂中具体的方法名)" />
	          

bean的种类

普通bean:之前操作的都是普通bean。 <bean id="" class="A"/>, spring直接创建A的实例并返回

FactoryBean:是一个特殊的bean,具有工厂生成对象的能力,只能生成特定的对象
	bean必须实现FactoryBean接口,此接口提供方法, getOeject() 用于获得特定的bean
	<bean id="" class="FB"/>先创建FB实例,使用调用getObject()方法,并返回方法的返回值
	==》FB fb=new FB();
		return fb.getObject();

BeanFactory和FactoryBean对比
	BeanFactory:工厂,用于生成任意bean。
	FactoryBean:特殊bean用于生成另一个特定的bean,例如:ProxyFactoryBean,此工厂bean用于生产代理。
				<bean id="" class="...ProxyFactoryBean" />获得代理对象实例,AOP使用

作用域

作用域:用于确定spring创建bean实例个数
        当在 Spring 中定义一个 bean 时,你必须声明该 bean 的作用域的选项。例如,为了强制 Spring 在每次需要时都产生一个新的 
        bean 实例,你应该声明 bean 的作用域的属性为 prototype。同理,如果你想让 Spring 在每次需要时都返回同一个bean实例,
        你应该声明 bean 的作用域的属性为 singleton。
        
	scope配置项有5个属性,用于描述不同的作用域。  
		<bean id="" class="...impl" scope=" " />

		① singleton(单例,默认值)

			在spring ioc容器中仅存在一个bean实例,bean以单例方式存在,默认值

		② prototype(多例)

			每次从容器中调用bean时,都返回一个新的实例,即每次调用getbean()时,相当于执行new xxxbean()

		③ request

			该属性仅对HTTP请求产生作用,使用该属性定义Bean时,每次HTTP请求都会创建一个新的Bean,适用于WebApplicationContext环境。

		④ session

			该属性仅用于HTTP Session,同一个Session共享一个Bean实例。不同Session使用不同的实例。

		⑤ global-session

			该属性仅用于HTTP Session,同session作用域不同的是,所有的Session共享一个Bean实例。



生命周期

初始化和销毁

    目标方法执行前、执行后,将进行初始化或销毁
        要求:1.容器必须close,销毁方法才能执行
            2.必须单例
                    1. ApplicationContext applicationContext = new ClassPathXmlApplicatonContext(xmlpath)
                        applicationContext.getClass().getMethod("close").invoke(applicationContext)
                        //ApplicationContext是接口  接口中没有定义,实现类提供 反射执行实现类

                    2. ClassPathXmlApplicatonContext applicationContext = new ClassPathXmlApplicatonContext(xmlpath)
                        applicationContext.close();

        <bean id="" class="" init-method="初始化方法名称" destroy-method="销毁的方法名称"/>


BeanPostProcessor后处理Bean
    spring提供一种机制,只要实现此接口BeanPostProcessor,并将实现类提供给spring容器,spring容器将自动执行
    。在初始化方法前执行before(),在初始化方法后执行after()
            
    spring提供工厂钩子,用于修改实例对象,可以生成代理对象,时aop底层
            A a = new A();
            a=B.before(a);    ----->将a的实例对象传递给后处理bean,可以生成代理对象并返回
            a.init();
            B.after(a);
            a.addUser();
            a.destroy();

属性依赖注入

setter注入
<bean id="personid" class="">
    <property name="pname" value="XXX"></property>
    <property name="age" >
        <value>1234</value>
    </property>
    
    <property name="homeaddr" ref="aaa"></property>

<bean id="aaa" class="">
	<property name="addr" value="XXX"></property>
</bean>



P命名空间(了解)

    对“setter方法注入”进行简化,替换<property name="属性名">,而是在
    <bean p:属性名="普通值" p:属性名-ref="引用值">

    p命名空间使用前提,必须添加命名空间
    引用约束:xmlns:p="..../schema/p"

例:<bean id="" class="" p:name="" p:age="" p:homeaddr-ref=""/>





SpEL(了解)

对<property>进行统一编程,所有的内容都使用value
<property name="" value="#{表达式}">
#{123}、#{'jack'} : 数字、字符串
#{beanId} : 另一个bean引用
#{beanId.propName} : 操作数据
#{beanId.toString} : 执行方法
#{T(类).字段|方法}   : 静态方法或字段




集合

集合的注入都是给<property>添加子标签
        数组: <array>
        List: <List>
        Set: <set>
        Map: <map>
        propertis: <props>
普通数据:<value>
引用数据:<ref>

例子:
<bean id="" class="">
    <property name="bean的属性">
        <array> (<list> <set>同理)
            <value>aaa</value>
            <value>bbb</value>
            <value>ccc</value>
        </array>
    </property>
    
    <property name="bean的属性">
        <map> 
            <entry key="" value=""></entry>
        </map>
    </property>
    
    <property name="bean的属性">
        <props> 
            <prop key="XXX" >XXX</prop>
        </props>
    </property>

装配bean基于注解

注解:就是一个类,取代@注解名称
开发中:使用注解,取代xml配置文件

需要引入dtd(命名空间的声明)
-------------------------------------------------------------
            <?xml version="1.0" encoding="UTF-8"?>
            <beans xmlns="http://www.springframework.org/schema/beans"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xmlns:context="http://www.springframework.org/schema/context"
                   xsi:schemaLocation="http://www.springframework.org/schema/beans
                                          http://www.springframework.org/schema/beans/spring-beans.xsd
                                          http://www.springframework.org/schema/context
                                          http://www.springframework.org/schema/context/spring-context.xsd">
                <!-- 组件扫描,扫描含有注解的类 -->
                <context:component-scan base-package="test"></context:component-scan>
            </beans>
--------------------------------------------------------------


1.@component 取代 <bean class="">
	@component("id") 取代 <bean id="" class="">

2.web开发,提供3个@component注解衍生注解(功能一样)
        @Repository:dao层
        @Service:service层
        @Controller:web层
 使用前先扫描包
        
3.依赖注入	给私有字段设置,也可以给setter方法设置
    普通值 @Value("")
    引用值
        方式1:按照【类型】注入
        	@Autowrired
        方式2:按照【名称】注入1
        	@Autowrired
       		@Qualifier("名称")
        方式3:按照【名称】注入2
            @Resource("名称")
            
            
            
@Required 
            注释应用于 bean 属性的 setter 方法,它表明受影响的 bean 属性在配置时必须放在 XML 配置文件中
			,否则容器就会抛出一个 BeanInitializationException 异常。下面显示的是一个使用 @Required 注释的示例。
@Qualifier
            可能会有这样一种情况,当你创建多个具有相同类型的 bean 时,并且想要用一个属性只为它们其中的一个进行装配,在这种
            情况下,你可以使用 @Qualifier 注释和 @Autowired 注释通过指定哪一个真正的 bean 将会被装配来消除混乱。


AOP

aop术语
    1.target:目标类,需要被代理的类,例如:UserService
    2.joinpoint:连接点,所谓连接点时值那些可能被拦截到的方法,例如:所有方法
    3.poincut:切入点,已经被加强的连接点,例如:add user()
    4.advice:通知/增强,增强代码。例如:after、before
    5.weaving:织入,指把增强advice应用到目标对象target来创建新的代理对象的过程
    6.proxy:代理类
    7.aspect:切面,是切入点pointcut和通知advice的结合
        一个线时一个特殊的面
        一个切入点和一个通知,组成一个特殊的面

AOP


手动代理

public static Userservice createservice(){
    //1.目标类
    Userservice userservice = new UserserviceImpl();
    
    //2.切面类
    MyAspect myaspect = new MyAspect();
    
    /* 3.代理类:将目标类(切入点)和切面类(通知)结合--》切面
    proxy.newProxyInstance
    参数1.loader,类加载器,动态代理类运行时创建,任何类都需要类加载器将其加载到内存
            一般情况:当前类:class.getClassLoader();
            		目标类实例:getClass().get...
    参数2.class[] interfaces 代理类需要实现的所有接口
             方式1.目标类实例:getClass().getInterfaces();    注意:只能获得自己的接口,不能获得父类元素的接口
             方式2.new Class[]{UserService.class}
             例如:jdbc驱动--》DriverManager   获得接口Connection
     
    参数3.InvocationHandler  处理类,接口,必须进行实现类,一般采用匿名内部类
        提供invoke方法,代理类的每一个方法执行时,都将调用一次invoke
        参数31:Object proxy:代理对象
        参数32:Method method:代理对象当前执行的方法的描述对象(反射)
        参数33:Object[] args:方法实际参数
     */
    
}

手动代理例子

UserService

package com.yjf.JDk;

public interface UserService {
	public void add();
	public void delete();
	public void find();
}

Myaspect

package com.yjf.JDk;

public class Myaspect {
	public void after() {
		System.out.println("------after");
	}
	public void before() {
		System.out.println("------befor");
	}
}

MybeanFactory

package com.yjf.JDk;

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

public class MybeanFactory {
	public static UserService creatservice() {
		 UserService userService=new UserServiceImpl();
		
		 Myaspect myaspect = new Myaspect();
		
		UserService proxyService=(UserService) Proxy.newProxyInstance(
				MybeanFactory.class.getClassLoader(),
				userService.getClass().getInterfaces(),
				new InvocationHandler() {
					
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						// TODO Auto-generated method stub
						myaspect.after();
						Object object=method.invoke(userService);
						myaspect.before();
						return object;
					}
				}
				);
		return proxyService;
	}
}

test

package com.yjf.JDk;

public class test {
public static void main(String[] args) {
	UserService u=MybeanFactory.creatservice();
	u.add();
	u.delete();
	u.find();
}
}

结果

------after
add---------
------befor
------after
delete---------
------befor
------after
find---------
------befor

原文地址:https://www.cnblogs.com/sm1128/p/10939582.html