IoC
控制反转Ioc(Inversion of Control),是一种设计思想,DI(依赖注入)是实现Ioc的一种方法。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
IoC创建对象方式
使用无参构造创建对象
实体类
package com.kuang.pojo;
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
ApplicationContext.xml
在resource目录下
<?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">
<!-- 使用Spring来创建对象,在Spring,这些都称Bean -->
<bean id="user" class="com.kuang.pojo.User">
//这个是利用实体类的set方法来进行注入的
//这个property作用是提前设置实体类的字段值,也可以不写property
<property name="name" value="pakhm" />
</bean>
</beans>
程序入口
public class MyTest{
public static void main(String[] args){
//获取Spring的上下文对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
//我们的对象现在都在Spring中的管理了,我们要使用,直接去里面取出来就可以
Hello hello =(Hello)applicationContext.getBean("hello");
System.out.println(hello);
}
}
使用有参构造创建对象
实体类
package com.kuang.pojo;
public class User {
private String name;
public User(String name){
this.name=name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
程序入口
public class MyTest{
public static void main(String[] args){
//获取Spring的上下文对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
//我们的对象现在都在Spring中的管理了,我们要使用,直接去里面取出来就可以
Hello hello =(Hello)applicationContext.getBean("hello");
System.out.println(hello);
}
}
三种方式
使用下标
在resource目录下ApplicationContext.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.xsd">
<!-- 使用Spring来创建对象,在Spring,这些都称Bean -->
<bean id="user" class="com.kuang.pojo.User">
<construtor-arg index="0" value="pakhm1" />
</bean>
</beans>
使用类型
在resource目录下ApplicationContext.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.xsd">
<!-- 使用Spring来创建对象,在Spring,这些都称Bean -->
<bean id="user" class="com.kuang.pojo.User">
<construtor-arg type="java.lang.String" value="pakhm2" />
</bean>
</beans>
缺陷:如果实体类有多个相同类型的字段,那么就不能用这种方式
使用字段名
在resource目录下ApplicationContext.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.xsd">
<!-- 使用Spring来创建对象,在Spring,这些都称Bean -->
<bean id="user" class="com.kuang.pojo.User">
<construtor-arg name="name" value="pakhm3" />
</bean>
</beans>
总结
在配置文件加载的时候,容器中管理的对象就已经初始化了
ApplicationContext.xml配置说明
beans
里面可以放多个bean
description
描述
alias
<alias name="user" alias="myUser"/>
name:bean的id
alias:别名
bean
注册配置bean
<bean id="userT" class="com.kuang.pojo.userT" name="user2 user3,user4;user5" scope="singleton">
...
</bean>
id:bean的唯一标识符
class:对象的全限定名称
name:别名,别名可以取多个,可以用空格、逗号、";"来取多个值
scope:bean的作用域,默认值是singleton
import
可以将多个配置文件导入合并为一
<import resource="xxx.xml" />
如果多个配置文件有内容相同的部分,那么会合并
DI依赖注入
(有参)构造器注入
上面 IoC创建对象方式
中的 使用有参构造创建对象
就是构造器注入
set方式注入
实体类
@Data
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbies;
private Map<String,String> card;
private Set<String> games;
private String wife;
private Properties info;
}
ApplicationContext.xml
在resource目录下
<?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">
<bean id="myAddress" class="com.kuang.pojo.Address" />
<bean id="student" class="com.kuang.pojo.Student">
//1.注入基本数据类型
<property name="name" value="pakhm" />
//2.注入我自己创建的类
<property name="address" ref="myAddress" />
//3.注入数组类型
<property name="books">
<array>
<value>西游记</value>
<value>三国演义</value>
<value>水浒传</value>
</array>
</property>
//4.注入List类型
<property name="hobbies">
<array>
<value>听歌</value>
<value>玩游戏</value>
</array>
</property>
//5.注入Map类型
<property name="card">
<map>
<entry key="身份证" value="123" />
<entry key="身份证" value="456" />
</map>
</property>
//5.注入Set类型
<property name="games">
<set>
<value>LOL</value>
<value>DNF</value>
</set>
</property>
//6.注入null
<property name="wife">
<null/>
</property>
//7.注入Properties类型
<property name="info">
<props>
<prop key="年龄">123</prop>
<prop key="身高">456</prop>
</props>
</property>
</bean>
</beans>
p命名空间注入
相当于set注入
的简化版
<bean name="jane" class="com.example.Person">
<property name="name" value="Jane Doe"/>
</bean>
<bean name="john-classic" class="com.example.Person">
<property name="name" value="Jane Doe"/>
<property name="spouse" ref="jane"/>
</bean>
//相当于
<bean name="john-modern" class="com.example.Person" p:name="Jane Doe" p:spouse-ref="jane" />
c命名空间注入
相当于(有参)构造器注入
的简化版
<bean name="beanTwo" class="x.y.ThingTwo"/>
<bean name="beanThree" class="x.y.ThingThree"/>
<bean id="beanOne" class="x.y.ThingOne">
<constructor-arg name="thingTwo" ref="beanTwo"/>
<constructor-arg name="thingThree" ref="beanThree"/>
<constructor-arg name="email" value="xx@qq.com"/>
</bean>
//相当于
<bean id="beanOne" class="x.y.ThingOne" c:thingTwo-ref:"beanTwo" c:thingThree-ref:"beanThree" c:email="xx@qq.com"/>
bean的作用域
singleton(单列模式)
<bean id="user2" class="com.kuang.pojo.User" c:age="19" c:name="pakhm" scope="singleton"/>
Spring默认机制,每次获取这个对象的时候,拿到的都是同一个对象,内存地址一样。
prototype(原型模式)
<bean id="user2" class="com.kuang.pojo.User" c:age="19" c:name="pakhm" scope="prototype"/>
每次获取这个对象的时候,拿到的都是不同的对象,内存地址不一样。
其他
request,session,application,websocket在web开发中使用到。
装配bean的方式
xml中显式配置
上面的DI依赖注入
就是xml中显式配置
java中显式配置
配置类
//这个也会Spring容器托管,注册到容器中,因为他本来就是一个@Component
//@Configuration代表这是一个配置类,就和我们之前看的ApplicationContext.xml
@Configuration
@ComponentScan("com.kuang.pojo")
@Import(KuangConfig2.class)
public class KuangConfig {
//注册一个bean,就相当于我们之前写的一个bean标签
//这个方法的名字,就相当于bean标签中的id属性
//这个方法的返回值,就相当于bean标签中的class属性
@Bean
public User user(){
return new User();
}
}
程序入口
public class MyTest{
public static void main(String[] args){
//如果完全使用了配置类方式去做,我们就只能通过AnnotationConfig上下文来获取容器,通过配置类的class对象加载
ApplicationContext context = new AnnotationConfigApplicationContext(KuangConfig.class);
User getUser=(User) context.getBean("user");
}
}
隐式的自动装配
实体类
@Data
public class Dog{
public void shout(){
System.out.println("wang~")
}
}
@Data
public class Cat{
public void shout(){
System.out.println("wang~")
}
}
@Data
public class People{
private Cat cat;
private Dog dog;
private String name;
}
ApplicationContext.xml
xml中显式配置
<bean id="cat" class="com.kuang.pojo.Cat" />
<bean id="dog" class="com.kuang.pojo.Dog" />
<bean id="people" class="com.kuang.pojo.People">
<property name="name" value="pakhm"/>
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
</bean>
byName
会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanId
要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致
<bean id="cat" class="com.kuang.pojo.Cat" />
<bean id="dog" class="com.kuang.pojo.Dog" />
<bean id="people" class="com.kuang.pojo.People" autowire="byName">
<property name="name" value="pakhm"/>
</bean>
byType
会自动在容器上下文中查找,和自己对象属性类型相同的bean
要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致
<bean id="cat" class="com.kuang.pojo.Cat" />
<bean id="dog" class="com.kuang.pojo.Dog" />
<bean id="people" class="com.kuang.pojo.People" />
注解
//开启注解支持
<context:annotation-config/>
<bean id="cat" class="com.kuang.pojo.Cat" />
<bean id="dog" class="com.kuang.pojo.Dog" />
<bean id="people" class="com.kuang.pojo.People" />
实体类中,在属性上、或者set方法上使用注解
使用@Autowired,我们可以不用编写Set方法了,前提是你这个自动装配的属性在IOC(Spring)容器中存在,且符合名字byName
@Autowired有一个参数required,默认值是true,如果这个值为false,说明这个属性可以为null,否则不允许为空
@Data
public class People{
@Autowired
private Cat cat;
@Autowired(required = false)
private Dog dog;
private String name;
}
@Autowired找bean的时候先用byType,如果找不到的话再用byName。如果这两个操作还不能找到bean的话我们可以使用@Qualifier来指定我们想要的bean,@Qualifier里面写beanId
@Data
public class People{
@Autowired
@Qualifier(value="xxx")
private Cat cat;
@Autowired
private Dog dog;
private String name;
}
@Resource注解也可以用来自动装配
@Resource找bean的时候先用byName,如果找不到的话再用byType。如果这两个操作还不能找到bean的话我们可以给@Resource里面写指定的beanId
@Data
public class People{
@Resource
private Cat cat;
@Resource(name="xxx")
private Dog dog;
private String name;
}
Spring注解开发
ApplicationContext.xml
//指定要扫描的包,这个包下的注解就会生效
<context:component-scan base-package="com.kuang.pojo" />
//开启注解支持
<context:annotation-config/>
实体类
//这个注解等价于 <bean id="user" class="com.kuang.pojo.User" />
@Component
//设置bean的作用域
@Scope("prototype")
@Data
public class User{
//这个注解相当于 <property name="name" value="pakhm"/>,这个注解也可以放在set方法上面
@Value("pakhm")
public String name;
}
Component衍生的注解
功能跟@Component一样,都是将某个类注册到Spring中,装配Bean
@Repository:用在dao层
@Service:用在service层
@Controller:用在controller层
AOP
环境准备
Spring实现AOP需要导入一个依赖包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
使用原生Spring API接口方式
MethodBeforeAdvice
方法执行之前
public class Log implements MethodBeforeAdvice {
//method:要执行的目标对象的方法
//args:参数
//target:目标对象
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了")
}
}
AfterReturningAdvice
方法执行之后
public class AfterLog implements AfterReturningAdvice {
//returnValue:返回值
public void afterReturning(Object returnValue,Method method,Object[] args,Object target){
System.out.println("执行了"+method.getName()+"方法,返回结果为:"+returnValue)
}
}
ApplicationContext.xml
<!-- 注册bean -->
<bean id="userService" class="com.kuang.service.UserServiceImpl" />
<bean id="log" class="com.kuang.log.Log" />
<bean id="afterLog" class="com.kuang.log.AfterLog" />
<!-- 配置AOP -->
<aop:config>
<!-- 切入点 -->
<aop:pointcut id="pointcut" expression="execution(* com.kuang.servie.UserServiceImpl.*(..))"></aop:pointcut>
<!-- 执行环绕增加 -->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"></aop:pointcut>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"></aop:pointcut>
</aop:config>