复杂类型注入
? 数组类型[]
? 集合类型 List Set Map Properties
<!--复杂类型注入--> xml
<bean id="complexModel" class="com.zhiyou100.pojo.ComplexObject">
<!--数组类型注入-->
<property name="arr">
<array>
<!--往arr属性中诸如具体的值 值可以注入一个也可以诸如多个 数量不限-->
<value>Java</value>
<value>C</value>
<!--往arr中注入一个对象类型-->
<ref bean="user1"></ref>
</array>
</property>
<!--List类型注入-->
<property name="myList">
<list>
<!--注入基本类型-->
<value>Python</value>
<value>PHP</value>
<!--注入引用类型-->
<ref bean="user2"></ref>
</list>
</property>
<!--set类型注入-->
<property name="mySet">
<set>
<!--注入基本类型-->
<value>C++</value>
<value>JavaScript</value>
<!--注入引用类型-->
<ref bean="user1"></ref>
</set>
</property>
<!--Map类型注入-->
<property name="myMap">
<map>
<!--注入基本类型-->
<entry key="课程" value="英语"></entry>
<entry key="专业" value="Java"></entry>
<!--注入引用类型-->
<entry key="计算机系" value-ref="user1"></entry>
</map>
</property>
<!--注入Properties-->
<property name="properties">
<props>
<prop key="sex">男</prop>
<prop key="gender">女</prop>
<prop key="sexuality">未知</prop>
</props>
</property>
备注:
以上使用的复杂类型,只要他存储结构相同,里面嵌套的标签可以混搭
如::Array,List,Set单列的结构,他们里面的子标签可以混用
Map,Properties双列结构,他们里面的子标签可以混用
Spring的分模块配置文件的开发
有时候我们为了方便阅读,会将配置文件按照不同功能,模块分成多个xml文件,在引入的时候可以使用<import>标签,
集成到当前的配置文件中.目的就是当程序读取该配置文件,就会把引入的其他配置文件全部读进内存当中.
注意事项:引入的时候,他是一个类路径(classes)也是一个相对路径
不同的Spring的配置文件 格式:如dao层 applicationContext-dao.xml
如service层 applicationContext-service.xml
如web层 applicationContext-mvc.xml
引入实例
<imprt resource = "applicationContext-xxx.xml"/>
注解开发
组件扫描
○ @Component
○ @Service
○ @Controller
○ @Repository
配置步骤
○ 再主配置文件中applicationContext.xml文件中添加组件扫描
<!--组件扫描 com.zhiyou100--> xml
<context:component-scan base-package="com.zhiyou100"/>
备注:他不但能扫描当前包中的类,还能扫描到他的子包中的类
○ 在该包下,需要被Spring扫描的类上面添加注解 @Component@Service@Controller@Repository 中的任何一个即可
○ 别名:在注解后面加括号里写别名
备注:
想要让Spring容器扫描到注入的类,那么就需要在该类上面添加这四个注解中的任意一个,否则无法正常注入.
就类似于给该类打上一个标记
这四个注解,如果不指定对象名字,系统默认分配一个名字,名字格式为:首字母小写;
但是如果在使用注解时,手动指定对象名字,那么将来获取该对象通过指定的名字获取.
@Scope注解配置对象的创建方式
@Scope(scopeName = "singleton")指定该对象在单例模式下创建对象,返回的都是同一个对象
@Scope(scopeName = "prototype")指定该对象在多例模式下创建对象,每次返回的都是新对象
生命周期方法
○ @PostConstruct 标记在初始化方法上面,构造方法执行之后调用
○ @PreDestroy 标记在销毁的方法上面,容器关闭前销毁
User类 pojo
//定义初始化方法
@PostConstruct
public void initUser(){
System.out.println("构造方法调用后初始化该对象信息");
}
//定义销毁的方法
@PreDestroy
public void destroyUser(){
System.out.println("容器关闭前销毁该对象");
}
备注:
如果想要执行销毁方法,那么需要手动关闭容器,才能看到销毁方法被调用
必须在单例模式种才支持
//关闭容器
((ClassPathXmlApplicationContext)context).close();
属性注入的注解
○ 简单类型=基本类型+String字符串类型
@Value 注入属性值
备注:该注解可以标记在属性上面,也可以标记在属性对应的set方法上面
○ 引用类型
§ @Autowired
根据容器中的类型进行自动匹配,进行注入.一般情况下如果Spring容器中有多个该类型,那么就会报期望的值和从容其中查到的值数量不匹配
//No qualifying bean of type ‘com.zhiyou100.pojo.User‘ available: expected single matching bean but found 3: user1,user2,user
§ @Qualifier
指定该属性引用容器中的哪一个Bean对象,@Autowired和@Qualifier搭配使用.
项目中,如果该类只在容器中配置一次,那么可以放心的使用@Autowired
§ @Resource
相当于@Autowired+@Qualifier
对于引用类型直接指定该属性注入哪个Bean对象
Spring纯注解开发
○ @Configuration
该注解是一个配置性的注解,指定当前类是一个Spring配置类
@Configuration
public class SpringConfiguration{
}
○ @ComponentScan
组件扫描注解 替代
<context:component-scan base-package="com.zhiyou100"/>
@Configuration
@ComponentScan("com.zhiyou100")//存放的是组件扫描的包名
public class SpringConfiguration{
}
○ @Bean
该注解只能写在方法上面,表明调用此方法会给你返回一个对象,存放到Spring容器中
等价于:
<bean id="car1" class="com.zhiyou100.pojo.Car" p:name="自行车" p:price="10"/>
public class DBUtil{
//使用CSP0
private final static DataSource dataSource = new ComboPooledDataSource();
@Bean
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}
○ @PropertySource
作用:主要是加载db.properties
@PropertySource("db.properties")
public class DBUtil{
@Value("${jdbc.driverClass}")
private String driver;
@Value("${jdbc.username}")
private String url
…
//创建一个连接
@Bean
public static Connection getConnection() throws SQLException {
DataSource dataSource = new ComboPooledDataSource();
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setJdbcUrl(driver);
dataSource.setUser(url);
return dataSource.getConnection();
}
}
db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///mybatis01?characterEncoding=UTF-8
jdbc.username=root
jdbc.password=root
○ @Import
作用:主要导入其他配置文件.导入配置类
等价于:
<import resource="applicationContext-service.xml"/>
@PropertySource("db.properties")
public class DBUtil{
@Value("${jdbc.driverClass}")
private String driver;
@Value("${jdbc.username}")
private String url
…
//创建一个连接
@Bean
public static Connection getConnection() throws SQLException {
DataSource dataSource = new ComboPooledDataSource();
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setJdbcUrl(driver);
dataSource.setUser(url);
return dataSource.getConnection();
}
}
主配置类
@Configuration
@ComponentScan("com.zhiyou100")//存放的是组件扫描的包名
@Import(DBUtil.class)
public class SpringConfiguration{
}
//测试 不能使用因为他是加载xml文件用的
ClassPathXmlApplicationContext("applicationContext.xml");
@Test
public void test01(){
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class)
context.getBean("bean元素对象名",对应字节码文件)
}
Spring整合JUnit单元测试
作用:
减少测试中不停的构建Spring容器,如以下代码,就可以省略掉
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class)
context.getBean("bean元素对象名",对应字节码文件);
开发步骤:
? 在pom.xml文件中添加spring-test 坐标依赖
? 在测试类上添加注解@RunWith(SpringJUnit4ClassRunner.class)该类SpringJUnit4ClassRunner类由他帮助我们创建Spring容器
? 在测试类上面添加注解@ContextConfiguration("classpath:applicationContext.xml")注意:此路径是一个类路径,也是一个相对路径
? 从容器中取出需要的bean元素
getBean()
采用注解的属性注入@Autowired @Resource
? 测试是否成功
AOP(面向切面编程)
Aspect Oriented Programming,也是一种编程思想,主要的工作就是对应用中的重复代码进行横向抽取
在运行过程中采用动态代理技术把一些代码内容植入到应用当中.目标方法中进行一个增强.
Spring中有两种代理模式
静态代理
JDK原生的 动态代理
//JDK 原生的
//主要是对应用当中的业务层进行增强
//Proxy jdk的一个代理类
//使用该类中的一个方法newProxyInstance()
//该方法中有三个参数
//ClassLoader:类加载器: 要求和目标对象是一样的类加载器 固定写法
//Class<?> interfaces: 实现的接口,要求和目标对象中实现的接口一样 固定写法
//InvocationHandle: 代理的方式 如何对目标对象进行增强 接口 匿名内部类
//在该接口当中定义了一个抽象方法 invoke()
//在该方法中也有三个参数:
/*
Object proxy:代理的目标对象
Method method:当前要执行的,目标对象中的方法
Object[] args:当前执行方法中用到的参数.
*/
代码示例:
原方法:
public User queryUserByUsername(String username){
//......
System.out.println("----------------------");
//......
return null;
}
原生动态代理
public UserService getProxyUserService(UserService userService){//UserService 接口 传入的参数值肯定是该接口的实现类
UserService us = (UserService) Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(), UserServiceImpl.class.getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("queryUserByUsername该方法开始执行了...");
Object obj = method.invoke(userService, args);//反射机制
System.out.println("queryUserByUsername该方法执行即将关闭...");
return obj;
}
});
return us;
}
测试
public static void main(String[] args){
Proxy01 proxy01 = new Proxy01();
UserService proxyUserService = proxy01.getProxyUserService(new UserServiceImpl());
User user = proxyUserService.queryUserByUsername("小苏");
System.out.println(user);
}
运行结果:
queryUserByUsername ÷ ?? ...
----------------------
queryUserByUsername ÷ ? м ? ...
null
第三方插件 cglib代理
/*
测试 动态代理 第二种方式 cglib
原理 不需要借助接口,一般情况下在继承关系中--->父子类
要求 目标类 不能是最终类 public final DemoClass{} 不能出现final
Enhancer 增强器类
create() 创建
参数:
class 字节码对象 目标对象中的字节码对象
callback ---> MethodInterceptor接口 方法拦截器 代理的方式
通过拦截器的方式实现对目标对象中的方法进行增强
采用匿名内部类的方式实现
MethodInterceptor定义了一个抽象方法
intercept() 拦截方法
拦截方法也有三个参数:
Object proxy: 代理的目标对象
Method method: 当前要执行的目标对象中的方法
Object[] objects: 当前执行方法中用到的参数
*/
示例代码
原方法:
public User queryUserByUsername(String username){
//......
System.out.println("----------------------");
//......
return null;
}
cglib动态代理
public UserService getProxyUserService(UserService us){
//us.getClass()获取字节码对象
UserService userService = (UserService)Enhancer.create(us.getClass(), new MethodInterceptor() {
//intercept拦截器
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("开启事务");//connection.setAutoCommit()
Object obj = method.invoke(us, objects);
System.out.println("提交事务");//commit()
return obj;
}
});
return userService;
}
JUnit测试:
@Test
public void test02(){
UserService proxyUserService = proxy02.getProxyUserService(userService);
User user = proxyUserService.queryUserByUsername("小孙");
System.out.println(user);
}
测试结果:
开启事务
----------------------
提交事务
null
java Spring复杂类型注入 注解开发 Spring整合JUnit单元测试 AOP(面向切面编程) 动态代理(原生,cglib)
原文:https://www.cnblogs.com/shangjinshuai/p/14483005.html