1、Spring实现依赖注入的四种方式
1.set注入:
<!--set注入-->
<bean id="emp" class="com.example.ditest.Emp">
<property name="ename" value="张三"></property>
<property name="age" value="19"></property>
</bean>
2.构造函数注入 :
<!--构造注入 1.先把 daoimpl 注册进来 2.在serveice 写一个构造函数依赖注入-->
<bean id="userMapper" class="com.example.mapper.SmsUserMapperImpl"></bean>
<bean id="userService" class="com.example.service.UserServiceImpl">
<constructor-arg ref="userMapper"></constructor-arg>
</bean>
3.p命名空间注入:
<bean id="唯一标识" class="类的全路径"
p:"属性1"="注入的值" p:"属性2"="注入的值" />
<bean id="唯一标识" class="类的全路径"
p:属性-ref="注入的Bean" />
4.注解注入 :
注解方式将Bean的定义信息和Bean实现类结合在一起
Spring提供的注解有:
1,@Component:实现Bean组件的定义
@Component
public class MyComponent {
// 类的实现...
}
2,@Repository:用于标注DAO类
@Repository("userDao")
<!-- 与在XML配置文件中编写<bean id="userDao" class="dao.impl.UserDaoImpl" />等效-->
public class UserDaoImpl implements UserDao {
…
}
3,@Service:用于标注业务类
@Service("userService")
public class UserServiceImpl implements UserService {
<!--使用@Autowired注解实现Bean的自动装配-->
@Autowired
<!--默认按类型匹配,可使用@Qualifier指定Bean的名称-->
@Qualifier("userDao")
<!--为dao属性注入名为userDao的Bean-->
private UserDao dao;
……
}
4,@Controller:用于标注控制器类
- 在目标类上添加@Controller注解,将其标记为一个控制器类:
@Controller
public class MyController {
// 控制器的实现...
}
记得在Spring配置文件中配置组件扫描,以便Spring容器能扫描实例化@Controller注解标记的控制器:
<context:component-scan base-package="com.example" />
这里的com.example
是目标类所在的包路径,用于指定需要扫描的组件所在的包。
在控制器类中定义处理请求的方法,可以使用@RequestMapping等注解来标注方法,指定请求的URL路径和请求方法:
@Controller
public class MyController {
@RequestMapping("/hello")
public String hello() {
// 处理请求的逻辑...
return "hello"; // 返回视图名
}
}
创建Spring MVC的DispatcherServlet,并将其配置在web.xml文件中:
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
在配置中,将DispatcherServlet映射到根路径"/",并指定Spring配置文件的位置。
通过以上步骤,就可以将一个类标记为一个Spring MVC的控制器,并使用@RequestMapping等注解来定义处理请求的方法。当用户请求对应的URL时,Spring MVC会调用相应的方法进行处理,并返回指定的视图。
@Controller注解是Spring MVC中非常常用的注解之一,它将控制器类标记为一个特殊的组件,用于处理用户请求。
最重要的需要扫描包中注解标注的类:
<?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="com.example"/>
</beans>
AspectJ
u面向切面的框架,它扩展了Java语言,定义了AOP语法,能够在编译期提供代码的织入
@AspectJ
uAspectJ 5新增的功能,使用JDK 5.0注解技术和正规的AspectJ切点表达式语言描述切面
Spring通过集成AspectJ框架实现了以注解的方式定义切面,使得配置文件的代码大大减少
u利用轻量级的字节码处理框架asm处理@AspectJ中所描述的方法参数名
注意事项:
使用@AspectJ,首先要保证所用的JDK是5.0或以上版本
二,不同数据类型注入
<!--不同数据类型注入 -->
<bean id="emp2" class="com.example.ditest.Emp">
<!--普通属性-->
<property name="ename" value="李四"></property>
<!--空字符串和null-->
<property name="age">
<null/>
</property>
<!--小于号在XML文档中用来定义标签的开始,不能随便使用-->
<!--解决方案一:使用xML实体来代替-->
<property name="loves" value="<>"/> <!--表示大于和小于-->
<!-- 解决方案二:使用CDATA节 -->
<property name="dept">
<!-- CDATA中的C代表Character,是文本、字符的含义,CDATA就表示纯文本数据-->
<!-- XML解析器看到CDATA节就知道这里是纯文本,就不会当作XML标签或属性来解析-->
<!--所以CDATA节中写什么符号都随意-->
<value><![CDATA[a < b]]></value>
</property>
三、单例模式(Singleton)
什么是单例模式?
保证整个系统中一个类只有一个对象的实例,实现这种功能的方式就叫单例模式。
为什么要用单例模式?
1、单例模式节省公共资源
比如:大家都要喝水,但是没必要每人家里都打一口井是吧,通常的做法是整个村里打一个井就够了,大家都从这个井里面打水喝。
对应到我们计算机里面,像日志管理、打印机、数据库连接池、应用配置。
2、单例模式方便控制
就像日志管理,如果多个人同时来写日志,你一笔我一笔那整个日志文件都乱七八糟,如果想要控制日志的正确性,那么必须要对关键的代码进行上锁,只能一个一个按照顺序来写,而单例模式只有一个人来向日志里写入信息方便控制,避免了这种多人干扰的问题出现。
实现单例模式的思路
1. 构造私有:
如果要保证一个类不能多次被实例化,那么我肯定要阻止对象被new 出来,所以需要把类的所有构造方法私有化。
2.以静态方法返回实例。
因为外界就不能通过new来获得对象,所以我们要通过提供类的方法来让外界获取对象实例。
3.确保对象实例只有一个。
只对类进行一次实例化,以后都直接获取第一次实例化的对象。
/**
* 单例模式案例
*/
public class Singleton {
//确保对象实例只有一个。
private static final Singleton singleton = new Singleton();
//构造方法私有
private Singleton() {
}
//以静态方法返回实例
public static Singleton getInstance() {
return singleton;
}
}
这里类的实例在类初始化的时候已经生成,不再进行第二次实例化了,而外界只能通过SingleCase.getInstance()方法来获取SingleCase对象, 所以这样就保证整个系统只能获取一个类的对象实例。
单例模式的两种实现方式(饿汉式、懒汉式)
一、饿汉式
饿汉模式,可以想象一个很饿的人,需要立马吃东西,饿汉模式便是这样,在类加载时就创建对象,由于在类加载时就创建单例,因此不存在线程安全问题
//饿汉式
public class SingletonDemo1 {
//私有化构造器
private SingletonDemo1() {
}
//类初始化时立即加载该对象
private static SingletonDemo1 instance = new SingletonDemo1();
//提供公共的获取方法,由于静态的instance在类加载时就创建,因此不存在线程安全问题
public static SingletonDemo1 getInstance() {
return instance;
}
}
//测试
class SingletonDemo1Test {
public static void main(String[] args) {
SingletonDemo1 instance = SingletonDemo1.getInstance();
SingletonDemo1 instance1 = SingletonDemo1.getInstance();
System.out.println(instance == instance1); //输出true
}
}
但饿汉式也存在一定的问题,即如果在该类里面存在大量开辟空间的语句,如很多数组或集合,但又不马上使用他们,这时这样的单例模式会消耗大量的内存,影响性能
二、懒汉式
顾名思义,懒汉式,就是懒,即在类加载时并不会立马创建单例对象,而是只生成一个单例的引用,即可以延时加载
//懒汉模式
public class SingletonDemo2 {
//私有化构造器
private SingletonDemo2() {
}
//只提供一个实例,并不创建对象
private static SingletonDemo2 instance;
//提供公共的获取方法,因为不是在类加载时就创建对象,因此存在线程安全问题,使用synchronized关键字保证线程安全,效率降低
public static synchronized SingletonDemo2 getInstance() {
if (instance == null) {
instance = new SingletonDemo2();
}
return instance;
}
}
//测试
class SingletonDemo2Test {
public static void main(String[] args) {
SingletonDemo2 instance = SingletonDemo2.getInstance();
SingletonDemo2 instance1 = SingletonDemo2.getInstance();
System.out.println(instance == instance1); //输出true
}
}
比较:
- 饿汉式:线程安全(不排除反射),调用效率高,不能延时加载
- 懒汉式:线程安全(不排除反射),调用效率不高,可以延时加载