文件架构
config:放需要代码配置的文件
dao:放操作代码的接口文件
dao.impl:放操作代码的实现文件,关键词implements进行实现
domain:放对象实例的文件
service:放服务代码的接口文件
service.impl:放服务代码的实现文件,关键词implements进行实现,实现用到的操作可引用dao.impl
IOC使用
IOC:控制反转
用处:容器控制对象的创建
正转:我们主动控制去获取依赖对象
反转:容器来查找及注入依赖对象,对象只是被动接受依赖对象
好处:松散耦合,功能复用
代理模式,两种:
- 1)接口代理(JDK 动态代理)
package cn.sm1234.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxyUtils {
/**
* 使用JDK动态代理获取代理对象
* target: 目标对象
* @return
*/
public static Object getProxy(final Object target){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(), // 和目标对象一样的类加载器
target.getClass().getInterfaces(), // 目标对象的接口列表
new InvocationHandler() {
//invoke: 这个方法在每次调用代理类对象的时候被执行啦!!!
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("记录日志");
//调用目标对象的方法(目标对象,传入参数)
return method.invoke(target, args);
}
});
}
}
- 2)子类代理(Cglib 子类代理)
区别接口代理,直接类使用
package cn.sm1234.proxy;
import java.lang.reflect.Method;
import cn.sm1234.service.impl.CustomerServiceImpl2;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibProxyUtils {
/**
* 使用Cglib工具创建目标对象的子类对象
* @param target
* @return
*/
public static Object getProxy(final Object target){
return Enhancer.create(CustomerServiceImpl2.class, new MethodInterceptor() {
//intercept:每次代理类对象执行方法的时候执行该方法
@Override
public Object intercept(Object arg0, Method method, Object[] arg2,
MethodProxy arg3) throws Throwable {
System.out.println("记录日志");
//调用目标对象的方法
return method.invoke(target, arg2);
}
});
}
}
scope
scope 配置,包括:
singleton:创建一个单例的对象
prototype:每次创建一个对象(多例的)
request:用在 web 项目中,保证一个请求创建一个对象
session: 用在 web 项目中,保证一个会话创建一个对象
scope 配置实际应用场景
1) action 对象:必须是多例的
2) service 对象:单例
3) dao 对象:单例
对象生命周期方法
- init-method: 初始化方法
- destroy-method: 销毁方法
<bean id="customerDao" class="cn.sm1234.dao.impl.CustomerDaoImpl" init-method="init" destroy-method="destroy"></bean>
常用注解
@Component :创建对象(普通的 Spring 项目)
@Repository:和@Component 的作用是一样,创建对象(分层项目,Dao 层)
@Service:和@Component 的作用是一样,创建对象(分层项目,Service 层)
@Controller:和@Component 的作用是一样,创建对象(分层项目,Web 层)
@Scope:单例和多例(XML 方式里 scope 配置):@Scope("prototype")
@PostConstruct: 初始化方法
@PreDestroy:销毁方法
AppicationContext 接口,用于初始化 SpringIOC 容器。
ClassPathXmlApplicationContext: 使用类路径方式初始化 ioc 容器(推荐)
ApplicationContext ac = new ClassPathXmlApplicationContext("cn/sm1234/test/applicationContext.xml");
FileSystemApplicationContext: 使用文件系统的方式初始化 ioc 容器
ApplicationContext ac = new FileSystemXmlApplicationContext("E:\\workspaces\\sm1234_spring\\ch01_02_spring_ioc_xml\\src\\applicationContext.xml");
ApplicationContext ac = new FileSystemXmlApplicationContext("./src/applicationContext.xml");
SpringIOC的XML方式
创建对象
<bean id="customerDao" class="cn.sm1234.dao.impl.CustomerDaoImpl"></bean>
依赖注入
构造方式参数注入
public CustomerServiceImpl(CustomerDao customerDao) {
super();
this.customerDao = customerDao;
}
<bean id="customerDao" class="cn.sm1234.dao.impl.CustomerDaoImpl"></bean>
<bean id="customerService" class="cn.sm1234.service.impl.CustomerServiceImpl">
<constructor-arg index="0" ref="customerDao"/>
</bean>
setter 方法注入(推荐使用)
public CustomerServiceImpl() {
super();
}
public void setCustomerDao(CustomerDao customerDao) {
this.customerDao = customerDao;
}
<bean id="customerDao" class="cn.sm1234.dao.impl.CustomerDaoImpl"></bean>
<bean id="customerService" class="cn.sm1234.service.impl.CustomerServiceImpl">
<property name="customerDao" ref="customerDao"/>
</bean>
p 名称空间注入
注意:p 名称空间简化 setter 方法注入,所以必须要有 setter 方法
p:属性 : 注入普通的数据(例如 String)
p:属性-ref:注入 JavaBean 对象(例如 CustomerDao)
xmlns:p="http://www.springframework.org/schema/p"
<bean id="customerDao" class="cn.sm1234.dao.impl.CustomerDaoImpl"></bean>
<bean id="customerService" class="cn.sm1234.service.impl.CustomerServiceImpl" p:customerDao-ref="customerDao" p:name="eric"/>
spEL 表达式注入
<bean id="customerDao" class="cn.sm1234.dao.impl.CustomerDaoImpl"></bean>
<bean id="customerService" class="cn.sm1234.service.impl.CustomerServiceImpl">
<property name="customerDao" value="#{customerDao}"/>
<property name="name" value="#{'eric'}"/>
</bean>
注入不同的数据类型(重点)
普通数据类型: 或者 value 属性
JavaBean 对象: 或者 ref 属性
数组:
List 集合:
Map 集合:
//1.普通数据类型
private String gender;
public void setGender(String gender) {
this.gender = gender;
}
//2.JavaBean类型
private Customer customer;
public void setCustomer(Customer customer) {
this.customer = customer;
}
//3.数组类型
private String[] addresses;
public void setAddresses(String[] addresses) {
this.addresses = addresses;
}
//4.List数组
private List<Customer> customerList;
public void setCustomerList(List<Customer> customerList) {
this.customerList = customerList;
}
//5.Map集合
private Map<String,Customer> customerMap;
public void setCustomerMap(Map<String, Customer> customerMap) {
this.customerMap = customerMap;
}
//6.Properties
private Properties customerProps;
public void setCustomerProps(Properties customerProps) {
this.customerProps = customerProps;
}
<bean id="c1" class="cn.sm1234.domain.Customer">
<property name="name" value="rose"/>
<property name="gender" value="女"/>
</bean>
<bean id="c2" class="cn.sm1234.domain.Customer">
<property name="name" value="lucy"/>
<property name="gender" value="女"/>
</bean>
<bean id="c3" class="cn.sm1234.domain.Customer">
<property name="name" value="lily"/>
<property name="gender" value="女"/>
</bean>
<!-- 注入不同的数据类型 -->
<bean id="customerService" class="cn.sm1234.service.impl.CustomerServiceImpl">
<!-- 1.普通类型 -->
<property name="gender">
<value>jack</value>
</property>
<!-- 2.JavaBean类型 -->
<property name="customer">
<ref bean="c1"/>
</property>
<!-- 3.数组类型 -->
<property name="addresses">
<array>
<value>北京</value>
<value>上海</value>
<value>广州</value>
</array>
</property>
<!-- 4.List集合 -->
<property name="customerList">
<list>
<ref bean="c1"/>
<ref bean="c2"/>
<ref bean="c3"/>
</list>
</property>
<!-- 5.Map集合 -->
<property name="customerMap">
<map>
<entry key="001" value-ref="c1"/>
<entry key="002" value-ref="c2"/>
<entry key="003" value-ref="c3"/>
</map>
</property>
<!-- 6.Properties类型 -->
<property name="customerProps">
<props>
<prop key="001">rose</prop>
<prop key="002">eric</prop>
<prop key="003">jack</prop>
</props>
</property>
</bean>
SpringIOC的注解方式
创建对象
依赖spring-aop的包,需导入
开启 springIOC 的注解功能,注意:要引入 context 的名称空间
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
<bean id="customerDao" class="cn.sm1234.dao.impl.CustomerDaoImpl"></bean>
<!-- 加载properties文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 开启springIOC注解功能 -->
<!-- base-package: IOC注解的类所在包 -->
<context:component-scan base-package="cn.sm1234"/>
// 默认名称为类名(首字母小写):customerDaoImpl
// <bean id="customerDaoImpl" class="xxx"/>
@Component
public class CustomerDaoImpl implements CustomerDao
.................
依赖注入
@Value
作用:注入普通数据类型
@Value("${url}")
private String url;
@Autowired
作用:自动根据类型注入
/**
*1)自动根据类型进入注入,直接赋值给变量(无需提供构造方法或者setter方法)
* 2)如果Spring环境中没有任何一个CustomerDao的类型,那么会注入失败
* 3)如果Spring环境中出现了多个CustomerDao的类型的对象,那么也会注入失败
*/
@Autowired
private CustomerDao customerDao;
@Qualifier
作用:指定注入的对象名称
当@Autowired: 出现多个相同类型的对象的时候,可以使用@Qulifier 指定需要注入的对象名称。
@Autowired
@Qualifier(value="customerDao2")
private CustomerDao customerDao;
@Resource
作用:既能够根据类型自动注入,也可以根据对象名称注入
@Resource(name="customerDao2")
private CustomerDao customerDao;
- @Autowired vs @Resource 注解的区别?
1) 注入的方式不一样:
@Autowired:只能根据类型注入,如果需要根据名称进行注入需要@Qualfier 注解的配合。
@Resource:既能够根据类型自动注入,也可以根据对象名称注入
2) 所属的标准不同
@Autowired 来自于 Spring 框架
@Resource 来自 JavaEE 标准
@Resource 注解比@Autowired 更加标准!
结论:推荐使用@Resource 注解来注入对象!