2. IoC(控制反转)的概念和作用 DI(依赖注入)
控制反转是通过依赖注入实现的。
IOC是指原先我们代码里面需要实现对象的创建、维护对象的依赖关系,反转给容器帮忙实现。那么就需要创建一个容器,同时需要一种描述来让容器知道需要创建的对象与对象的关系。依赖注入的目的是为了解耦,体现一种组合的“理念”。继承一个父类,子类将于父类耦合,组合关系使耦合度大大降低。
耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。耦合的强弱取决于模块间接口的复杂性、调用模块的方式以及通过界面传送数据的多少。模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用关系、数据传递关系。模块间联系越多,其耦合性越强,同时表明其独立性越差( 降低耦合性,可以提高其独立性)。软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准。划分模块的一个准则就是高内聚低耦合。
Spring IOC 容器负责创建Bean,并通过容器将Bean注入到需要的Bean对象上。同时Spring IOC容器还负责维护Bean对象与Bean对象之间的关系。那么,Spring IOC如何来体现对象与对象之间的关系呢?Spring提供XML配置和Java配置等方式。下面来个例子:
User 实体被UserDao,UserService和UserServlet所依赖
实现这些类:
UserDao:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.util.*;
@AllArgsConstructor
@Data
@NoArgsConstructor
@ToString
public class User {
private int id;
private String name;
private int age;
private char sex;
//List集合
private List<String> photos;
private String[] friends;
private Set<String> money;
private Map<String,String> map;
private Properties properties;
}
UserDao
import lombok.Setter;
@Setter
public class UserDao {
private String url;
private String driverClass;
private String username;
private String password;
public User findUser(){
User u = new User (1000,"张三",21,'M',null,null,null,null,null);
return u;
}
}
UserSerivce
import lombok.Data;
@Data
public class UserService {
private UserDao userDao = null;
public User findUser () {
return userDao.findUser ();
}
}
UserServlet
import lombok.Data;
@Data
public class UserServlet {
private UserService userService;
public void findUser(){
System.out.println ("spring工厂的实例:");
System.out.println (userService.findUser());
}
}
在pomxml中添加Spring 核心库的依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>edu.xatu</groupId>
<artifactId>IOC</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
</project>
创建配置文件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">
<bean id="userServlet" class="edu.xatu.UserServlet" scope="singleton"><!--scope="singleton" singleton单例 scope="prototype"多例-->
<property name="userService" ref="service"/>
</bean>
<bean id="service" class="edu.xatu.UserService" autowire="byType"><!--autowire="byType"表示根据类型自动注入,但是只能有一个类型,不然无法区分-->
<!--<property name="userDao" ref="userDao"/>-->
</bean>
<bean class="edu.xatu.UserDao" id="userDao">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/cms"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</bean>
<bean id="user" class="edu.xatu.User">
<!-- <constructor-arg value="1111"/>
<constructor-arg value="张三"/>
<constructor-arg value="20"/>
<constructor-arg value="M"/>-->
<property name="photos">
<list>
<value>1.jpg</value>
<value>2.jpg</value>
<value>3.jpg</value>
<value>4.jpg</value>
</list>
</property>
<property name="friends">
<array>
<value>张三</value>
<value>李四</value>
<value>王阿门</value>
<value>胡</value>
</array>
</property>
<property name="money">
<set>
<value>人民币</value>
<value>美元</value>
<value>日元</value>
<value>欧元</value>
<value>英镑</value>
</set>
</property>
<property name="map">
<map>
<entry key="A" value="aaa"></entry>
<entry key="B" value="bbb"></entry>
<entry key="C" value="ccc"></entry>
<entry key="D" value="ddd"></entry>
</map>
</property>
<property name="properties">
<props>
<prop key="22">nscbhj</prop>
<prop key="27">djbschj</prop>
<prop key="24">5156</prop>
<prop key="65">式</prop>
</props>
</property>
</bean>
<bean id="factorybean" class="edu.xatu.FactoryBean"/>
<bean id="mybean" factory-bean="factorybean" factory-method="createUser"/>
<!--利用静态工厂bean方法创建实例-->
<bean id="factory1" class="edu.xatu.FactoryBean" factory-method="createStaticUser"/>
</beans>
创建FactoryBean类:
public class FactoryBean {
/**
* 非静态方法(实例方法)
*/
public User createUser(){
return new User ( );
}
/**
* 静态方法
*/
public static User createStaticUser(){
User u = new User (1000,"张三",21,'M',null,null,null,null,null);
return u;
}
}
测试类Test
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main (String[] args) {
//创建工厂
BeanFactory factory = new ClassPathXmlApplicationContext ( "applicationContext.xml" );
//根据Bean的id找Bean
UserServlet servlet = (UserServlet) factory.getBean ( "userServlet" );
UserServlet servlet1 = (UserServlet) factory.getBean ( "userServlet" );
System.out.println (servlet == servlet1);
System.out.println (factory.getBean ( "user" ));
servlet.findUser ();
}
}
测试结果:
true
User(id=0, name=null, age=0, sex= , photos=[1.jpg, 2.jpg, 3.jpg, 4.jpg], friends=[张三, 李四, 王阿门, 胡], money=[人民币, 美元, 日元, 欧元, 英镑], map={A=aaa, B=bbb, C=ccc, D=ddd}, properties={27=djbschj, 24=5156, 22=nscbhj, 65=式})
spring工厂的实例:
User(id=1000, name=张三, age=21, sex=M, photos=null, friends=null, money=null, map=null, properties=null)
这是怎么实现的呢?
首先是在main函数中根据applicationContext.xml创建工厂
BeanFactory factory = new ClassPathXmlApplicationContext ( "applicationContext.xml" );
接着根据applicationContext.xml中的bean 属性中的id值userServlet,找到类UserServlet,工厂通过反射实例化,同理其他方法也是如此。
<bean id="userServlet" class="edu.xatu.UserServlet" scope="singleton"><!--scope="singleton" singleton单例 scope="prototype"多例-->
<property name="userService" ref="service"/>
</bean>
<bean id="service" class="edu.xatu.UserService" autowire="byType"><!--autowire="byType"表示根据类型自动注入,但是只能有一个类型,不然无法区分-->
<property name="userDao" ref="userDao"/>
</bean>
<bean class="edu.xatu.UserDao" id="userDao">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/cms"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</bean>
<bean id="user" class="edu.xatu.User">
<!-- <constructor-arg value="1111"/>
<constructor-arg value="张三"/>
<constructor-arg value="20"/>
<constructor-arg value="M"/>-->
<property name="photos">
...
实例化完成后,就进行逻辑处理。
2.1注解:
@Compent 没有明确的注解
@Controller 主要用到web(控制层)
@Service 服务service(业务逻辑)层
@Repository 数据访问层 dao层
@Autowired 默认按类型装配。默认情况下要求依赖对象必须存在,如果允许为null值,可以设置它的required属性为false,如:@Autowired(required=false)
@Qualifier(“ser”) 和@Autowired结合使用,根据名称进行装配
@Resource相当中@Autowired加@Qualifier(“ser”),即可根据类型进行装配,也可以根据名称进行装配
2.2pom.xml
配置的依赖是各种组件的坐标,例如:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
写在这个文件里面的依赖,idea会从中央库下载这些组件。
2.3lombok组件
Lombok能以简单的注解形式来简化java代码,提高开发人员的开发效率。
@Setter就代替了生成出来的Setter方法,以下同理
@Data
@Value
@ToString
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
@RequiredArgsConstructor
@Getter