Spring
IOC(控制反转):面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
控制的过程:指谁来控制对象的创建。传统对象的创建是由程序本身控制的,使用spring后,是由spring来创建对象的。
反转:正转指程序来创建对象,反转指程序本身不去创建对象,而变为被动接受对象。
以前对象是由程序本身来创建,使用spring后,程序变为被动接受由spring创建的对象。
实例类:
package com.tedu.pojo; public class User { private String name; private Integer age; private UserInfo info; public User() { } public User(String name, Integer age, UserInfo info) { this.name = name; this.age = age; this.info = info; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public UserInfo getInfo() { return info; } public void setInfo(UserInfo info) { this.info = info; } public void show() { System.out.println("别把独孤当做晚餐"); } @Override public String toString() { return "User [name=" + name + ", age=" + age + ", info=" + info + "]"; } } class UserInfo { }
applicationContenxt.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-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"> <!--scop: singleton(默认):单实例,只会创建一个对象 prototype:多实例,每次创建都有一个新的对象返回 --> <!-- <bean id="user" class="com.tedu.pojo.User" scope="singleton"> <property name="name" value="啊"></property> <property name="age" value="18"> </property> <property name="info" ref="userInfo"></property> </bean> --> <bean id="user" class="com.tedu.pojo.User" scope=""> <constructor-arg name="name" value="波波"/> <constructor-arg name="age" value="20"/> <constructor-arg name="info" ref="userInfo"/> </bean> <!-- 将UsrInfo类注册到spring容器中 --> <bean id="userInfo" class="com.tedu.pojo.UserInfo"></bean> </beans>
测试类:
package com.tedu.spring; import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.tedu.pojo.User; /** * 1.测试spring的IOC * a).提供一个User类 * b).通过一个spring容器获取User类的实例 * 2.测试bean对象的单实例和多实例 * a)单实例:从头到尾只创建一个对象 * b)多实例:每次都是一个新的对象 * * */ public class TestSpring { @Test public void TestIOC() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); User user = (User)context.getBean("user"); User user2 = (User)context.getBean("user"); user.show(); if(user == user2) { System.out.println("当前对象是单实例"); }else { System.out.println("当前对象是单实例"); } } /** * 3.测试springDI(依赖注入) * 在创建的同时或之后为对象的属性赋值 * */ @Test public void testDI() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); User u1 = (User)context.getBean("user"); System.out.println(u1); } }
ioc创建对象的方式:
1.通过无参构造方法来创建
<bean id="user" class="com.tedu.pojo.User" scope="singleton"> <property name="name" value="啊"></property> <property name="age" value="18"> </property> <property name="info" ref="userInfo"></property> </bean>
2.通过有参构造方法来创建(需要有有参构造方法)
<bean id="user" class="com.tedu.pojo.User" scope=""> <constructor-arg name="name" value="波波"/> <constructor-arg name="age" value="20"/> <constructor-arg name="info" ref="userInfo"/> </bean>
3.通过工厂方法创建
a.静态工厂
public class UserFactory { public static User newInstance(String name) { return new User(name); } } class User { private String name; public User() { } public User(String name) { } }
<bean id="user" class="com.factory.UserFactory" factory-method="newInstance"> <constructor-arg name="name" value="啊啊啊"/> </bean>
b.动态工厂
public class UserFactory { public User newInstance(String name) { return new User(name); } } class User { private String name; public User() { } public User(String name) { } }
<bean id="userFactory" class="com.factory.UserFactory" /> <bean id="user" factory-bean="userFactory" factory-method="newInstance"> <constructor-arg name="name" value="啊啊啊"/> </bean>
依赖注入:
依赖:只bean对象创建依赖与容器。Bean对象额依赖资源。
注入:指bean对象依赖的资源由容器来设置和装配。
1.构造器注入(同IOC构造方法注入)
2.setter注入
要求被注入的属性必须有set方法,Set方法的方法名是由set+属性首字母大写。如果属性是boolean,没有get方法,是is.
a.常量注入
<bean id="user" class="com.tedu.pojo.User" scope="singleton"> <property name="name" value="啊"></property> <property name="age" value="18"> </property> </bean>
b.bean注入
<bean id="user" class="com.tedu.pojo.User" scope="singleton"> <property name="info" ref="userInfo"></property> </bean> <bean id="userinfo" class="com.tedu.pojo.UserInfo" scope="singleton"></bean>
c.数组注入
<bean id="user" class="com.tedu.pojo.User" scope="singleton"> <property name="books" <array> <value>傲慢与偏见</value> <value>仲夏夜之梦</value> </array> </property> <property name="info" ref="userInfo"></property> </bean>
d.list注入(Map,Set,...)
<bean id="user" class="com.tedu.pojo.User" scope="singleton"> <property name="books" <list> <value>傲慢与偏见</value> <value>仲夏夜之梦</value> </list> </property> <property name="info" ref="userInfo"></property> </bean>
e.Null注入
<bean id="user" class="com.tedu.pojo.User" scope="singleton"> <property name="books" <property name="wife" <null>></property> </bean>
h.Properties注入
<bean id="user" class="com.tedu.pojo.User" scope="singleton"> <property name="info" > <props> </props> <prop key="学号">2016061531</prop> <prop key="sex">男</prop> </property> </bean>
f.命名空间注入
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="myDataSource" class="com.jdbc" destroy-method="close" p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost:3306/mydb" p:username="root" p:password="masterkaoli"/> </beans>
g.c命名空间注入
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="myDataSource" class="com.info" c:name="nico" c:age="16"/> </beans>
bean的作用域:
singleton单例:整个容器中只有一个对象实例(默认是单例)。
prototype原型:每次获取bean都产生一个新的对象。
rquest:每次请求时创建一个新的对象。
session:在会话的1范围内是一个对象
gloabal session:只在portlet下有用,表示是application.
application:在应用范围内是一个对象。
bean的自动装配:autowire byName 根据名称去查找相应的bean ,如果有则装配。
<bean id="user" class="com.tedu.pojo.User" scope="singleton" autowire="byName"> <property name="name" value="啊"></property> <property name="age" value="18"> </property> </bean>
byType 根据类型自动装配,不用管bean的id,但是同一种类型的bean只有一个
<bean id="user" class="com.tedu.pojo.User" scope="singleton" autowire="byType"> <property name="name" value="啊"></property> <property name="age" value="18"> </property> </bean>
constructor 当通过构造器注入实例化bean时,使用byType的方式装配构造方法。
代理:
a.静态代理:
抽象角色:一般使用接口和抽象类实现。
真实角色:被代理的角色。
代理角色:代理真实角色-代理真实角色后一般会做一些附属操作。
客户:使用代理角色来进行操作。
使用静态代理的好处:
使得真实角色处理业务更加纯粹,不再去关注一些公共的事情、
公共的业务有代理来完成,实现业务的分工、
公共业务发生扩展时变得更加集中和方便、
缺点:
新增了代理类,工作量变大。
开发效率降低了
b.动态代理
1.动态代理和静态代理的角色是一样的。
2.动态代理的代理类是自动生成的。
3.分为两类:接口动态代理和类的动态代理
a.基于接口动态代理 :jdk动态代理
b.基于类的动态代理:cglib
现在javasist来生成动态代理
4.jdk动态代理 Proxy类和invocationHandler接口
AOP,一般称为面向切面,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理。
AOP实现的关键在于 代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。
(1)AspectJ是静态代理的增强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,他会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。
(2)Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:
①JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。
②如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
(3)静态代理与动态代理区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。
InvocationHandler 的 invoke(Object proxy,Method method,Object[] args):proxy是最终生成的代理实例; method 是被代理目标实例的某个具体方法; args 是被代理目标实例某个方法的具体入参, 在方法反射调用时使用。