⑴ spring在多線程中怎麼注入bean
Java(多)線程中注入Spring的Bean
問題說明
今天在web應用中用到了Java多線程的技術來並發處理一些業務,但在執行時一直會報NullPointerException的錯誤,問題定位了一下發現是線程中的Spring bean沒有被注入,bean對象的值為null。
原因分析
web容器在啟動應用時,並沒有提前將線程中的bean注入(在線程啟動前,web容易也是無法感知的)
解決方案
方法有多種,網上也看到了不少。
1. 使用static聲明變數
http://blog.csdn.net/bjamosgavin/article/details/6125497
這個方法自己試了一下但是沒有成功。。。
2. 把線程設置為主程序的內部類
這也是一種簡單的方法,主程序在web容器載入時肯定是可以注入Spring bean的,那麼將線程的實現類放在主程序的類中便可以「共享」Spring的bean,(當然,這需要提前把線程中的需要用到的bean定義在外層的類中)。
具體操作方法,就是將生成線程的線程池定義在主程序的類中,每個線程的實現類作為內部類也定義在主程序中。這個方法自己試過,是可以的。
3. 使用靜態方法直接取的容器中的spring對象
這個方法稍微專業點,可以線程的分發與線程的實現分離出來。在每個線程中使用靜態方法直接取的容器中的spring對象。
使用靜態方法獲取容器中的spring對象可以參見
http://littie1987.iteye.com/blog/937877,
或者http://my.oschina.net/skyline520/blog/181158?p={{page}}
但一定要記住,你定義這個工具類也要配置成spring中的bean!
下面貼一下我在使用時的代碼
(1)定義工具類
public class implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
.context = context;
}
public static Object getSpringBean(String beanName) {
notEmpty(beanName, "bean name is required");
return context==null?null:context.getBean(beanName);
}
public static String[] getBeanDefinitionNames() {
return context.getBeanDefinitionNames();
}
⑵ servlet容器在啟動web應用時創建哪些對象
Servlet容器 —— 以tomcat為例
在tomcat容器等級中,context容器直接管理servlet在容器中的包裝類Wrapper,所以Context容器如何運行將直接影響servlet的工作方式。
tomcat容器模型如下:
一個context對應一個web工程,在tomcat的配置文件server.xml中,可以發現context的配置(在eclipse工程中,可在部署路徑的conf文件夾zhoing找到)
[html] view plain在CODE上查看代碼片派生到我的代碼片
Context docBase="/Users/wongrobin/all/projects/tech-test/java-test/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/base-webapp" path="/base-webapp" reloadable="true" source="org.eclipse.jst.j2ee.server:base-webapp"/>
Servlet容器的啟動過程——以tomcat為例
Tomcat7增加了一個啟動類:
[html] view plain在CODE上查看代碼片派生到我的代碼片
org.apache.catalina.startup.Tomcat
創建一個Tomcat的一個實例對象並調用start方法就可以啟動tomcat。
還可以通過這個對象來增加和修改tomcat的配置參數,如可以動態增加context,servlet等。
在tomcat7中提供的example中,看是如何添加到context容器中:
[java] view plain在CODE上查看代碼片派生到我的代碼片
Tomcat tomcat = getTomcatInstance();
File appDir = new File(getBuildDirectory(), "webapps/examples");
tomcat.addWebapp(null, "/examples", appDir.getAbsolutePath());
tomcat.start();
ByteChunk res = getUrl("http://localhost:" + getPort() +
"/examples/servlets/servlet/HelloWorldExample");
assertTrue(res.toString().indexOf("<h1>Hello World!</h1>") > 0);
這段代碼創建了一個Tomcat實例並新增了一個WEB應用,然後啟動Tomcat並調用其中的一個HelloWorldExampleServlet。
Tomcat的addWebap方法的代碼如下:
[java] view plain在CODE上查看代碼片派生到我的代碼片
public Context addWebapp(Host host, String url, String path) {
silence(url);
Context ctx = new StandardContext();
ctx.setPath( url );
ctx.setDocBase(path);
if (defaultRealm == null) {
initSimpleAuth();
}
ctx.setRealm(defaultRealm);
ctx.addLifecycleListener(new DefaultWebXmlListener());
ContextConfig ctxCfg = new ContextConfig();
ctx.addLifecycleListener(ctxCfg);
ctxCfg.setDefaultWebXml("org/apache/catalin/startup/NO_DEFAULT_XML");
if (host == null) {
getHost().addChild(ctx);
} else {
host.addChild(ctx);
}
return ctx;
}
一個WEB應用對應一個context容器,也就是servlet運行時的servlet容器。添加一個web應用時將會創建一個StandardContext容器,並且給這個context容器設置必要的參數,url和path分別代表這個應用在tomcat中的訪問路徑和這個應用實際的物理路徑,這兩個參數與tomcat配置中的兩個參數是一致的。其中一個最重要的一個配置是ContextConfig,這個類會負責整個web應用配置的解析工作。
最後將這個context容器加入到父容器host中。
接下來會調用tomcat的start方法啟動tomcat。
Tomcat的啟動邏輯是基於觀察者模式的,所有的容器都會繼承Lifecycle介面,它管理著容器的整個生命周期,所有容器的修改和狀態改變都會由它通知已經注冊的觀察者。
Tomcat啟動的時序如下:
當context容器初始狀態設置Init時,添加到context容器的listener將會被調用。ContextConfig繼承了LifecycleListener介面,它是在調用Tomcat.addWebapp時被加入到StandardContext容器中的。ContextConfig類會負責整個WEB應用的配置文件的解析工作。
ContextConfig的init方法將會主要完成一下工作:
創建用於解析XML配置文件的contextDigester對象
讀取默認的context.xml文件,如果存在則解析它
讀取默認的Host配置文件,如果存在則解析它
讀取默認的Context自身的配置文件,如果存在則解析它
設置Context的DocBase
ContextConfig的init方法完成後,Context容器會執行startInternal方法,這個方法包括如下幾個部分:
創建讀取資源文件的對象
創建ClassLoader對象
設置應用的工作目錄
啟動相關的輔助類,如logger,realm,resources等
修改啟動狀態,通知感興趣的觀察者
子容器的初始化
獲取ServletContext並設置必要的參數
初始化「load on startuo」的Servlet
Web應用的初始化工作——以tomcat為例
WEB應用的初始化工作是在ContextConfig的configureStart方法中實現的,應用的初始化工作主要是解析web.xml文件,這個文件是一個WEB應用的入口。
Tomcat首先會找globalWebXml,這個文件的搜索路徑是engine的工作目錄下的org/apache/catalina/startup/NO-DEFAULT_XML或conf/web.xml。接著會找hostWebXml,這個文件可能會在System.getProperty("catalina.base")/conf/${EngineName}/${HostName}/web.xml.default中。接著尋找應用的配置文件examples/WEB-INF/web.xml,web.xml文件中的各個配置項將會被解析成相應的屬性保存在WebXml對象中。接下來會講WebXml對象中的屬性設置到context容器中,這里包括創建servlet對象,filter,listerner等,這些在WebXml的configureContext方法中。
下面是解析servlet的代碼對象:
[java] view plain在CODE上查看代碼片派生到我的代碼片
for (ServletDef servlet : servlets.values()) {
Wrapper wrapper = context.createWrapper();
String jspFile = servlet.getJspFile();
if (jspFile != null) {
wrapper.setJspFile(jspFile);
}
if (servlet.getLoadOnStartup() != null) {
wrapper.setLoadOnStartup(servlet.getLoadOnStartup().intValue());
}
if (servlet.getEnabled() != null) {
wrapper.setEnabled(servlet.getEnabled().booleanValue());
}
wrapper.setName(servlet.getServletName());
Map<String,String> params = servlet.getParameterMap();
for (Entry<String, String> entry : params.entrySet()) {
wrapper.addInitParameter(entry.getKey(), entry.getValue());
}
wrapper.setRunAs(servlet.getRunAs());
Set<SecurityRoleRef> roleRefs = servlet.getSecurityRoleRefs();
for (SecurityRoleRef roleRef : roleRefs) {
wrapper.addSecurityReference(roleRef.getName(), roleRef.getLink());
}
wrapper.setServletClass(servlet.getServletClass());
MultipartDef multipartdef = servlet.getMultipartDef();
if (multipartdef != null) {
if (multipartdef.getMaxFileSize() != null &&
multipartdef.getMaxRequestSize()!= null &&
multipartdef.getFileSizeThreshold() != null) {
wrapper.setMultipartConfigElement(new MultipartConfigElement(
multipartdef.getLocation(),
Long.parseLong(multipartdef.getMaxFileSize()),
Long.parseLong(multipartdef.getMaxRequestSize()),
Integer.parseInt(
multipartdef.getFileSizeThreshold())));
} else {
wrapper.setMultipartConfigElement(new MultipartConfigElement(
multipartdef.getLocation()));
}
}
if (servlet.getAsyncSupported() != null) {
wrapper.setAsyncSupported(
servlet.getAsyncSupported().booleanValue());
}
context.addChild(wrapper);
}
上面的代碼將servlet容器包裝成context容器中的StandardWrapper。StandardWrapper是tomcat容器中的一部分,它具有容器的特徵,而Servlet作為一個獨立的web開發標准,不應該強制耦合在tomcat中。
除了將Servlet包裝成StandardWrapper並作為子容器添加到Context中外,其他所有的web.xml屬性都被解析到Context中。
創建Servlet實例——以tomcat為例
前面完成了servlet的解析工作,並且被包裝成了StandardWrapper添加到Context容器中,但是它仍然不能為我們工作,它還沒有被實例化。
創建Servlet對象
如果Servlet的load-on-startup配置項大於0,那麼在Context容器啟動時就會被實例化。
前面提到的在解析配置文件時會讀取默認的globalWebXml,在conf下的web.xml文件中定義了一些默認的配置項,其中定義了兩個Servlet,分別是org.apache.catalina.servlets.DefaultServlet和org.apache.jsper.servlet.JspServelt,它們的load-on-startup分別是1和3,也就是當tomcat啟動時這兩個servlet就會被啟動。
創建Servlet實例的方式是從Wrapper.loadServlet開始的,loadServlet方法要完成的就是獲取servletClass,然後把它交給InstanceManager去創建一個基於servletClass.class的對象。如果這個Servlet配置了jsp-file,那麼這個servletClass就是在conf/web.xml中定義的org.apache.jasper.servlet.JspServlet。
初始化Servlet對象
初始化Servlet在StandardWrapper的initServlet方法中,這個方法很簡單,就是調用Servlet的init()方法,同時把包裝了StandardWrapper對象的StandardWrapperFacade作為ServletConfig傳給Servlet。
如果該Servlet關聯的是一個JSP文件,那麼前面初始化的就是JspServlet,接下來會模擬一次簡單請求,請求調用這個JSP文件,以便編譯這個JSP文件為類,並初始化這個類。
這樣Servlet對象的初始化就完成了。
容器默認Servlet
每個servlet容器都有一個默認的servlet,一般都叫做default。
例如:tomcat中的 DefaultServlet 和 JspServlet (上面的部分)
⑶ 關於Spring依賴注入的問題
首先類載入和sping配置文件載入的順序要理清楚。
1、web容器啟動,開始掃描所有被指定的spring配置文件。
2、根據配置文件,實例化所有的bean對象,以java語法創建。
3、載入spring配置文件配置的對象依賴關系,將有依賴關系的bean注入到相應的對象中。
你這里報錯是因為,datasource對象還沒有被注入到UserDaoImpl中,而此時UserDaoImpl被實例化,datasource對象仍為空,所以報錯了。
⑷ spring容器已經啟動,我怎麼動態的載入裡面的某個bean
[引文]通常在struts2+spring的例子上,要想使用spring的Bean,可以在applicationContext.xml加上如下配置
<bean id="springBean" scope="prototype" class=""
<property name="name" value="chen"/</bean<bean id="myAction" scope="prototype" class=""
<property name="springBean" ref="springBean"/</bean如果是j2ee應用,啟動web應用時將會自動載入ApplicationContext實例(Spring容器負責創建Bean實例)
一旦struts2的myAction實例化,其中的SpringBean也會被自動注入進來,從而達到使用SpringBean的目的。
[問題]但是仍有需要通過代碼來調用SpringBean的情況:
1)對於不是由spring創建管理的類,如在java 代碼中直接使用new去創建一個對象,並且想在這個對象中使用
SpringBean;因為這個對象並不是由Spring容器創建管理的類,所以即使它有setter方法,容器的springBean也不會被注入。
2)動態更改springBean中的屬性值,如在代碼運行時,name值需要發生變動;
3)對於一個獨立的應用程序[解決]定義一個非Spring容器創建管理的類
public class NonSpringClass implements ServletContextAware {
private SpringBean springBean;
//如果 testGetBean不是被Spring容器創建管理,即使它有setter方法,容器的springBean也不會被注入。
public void setSpringBean(SpringBean springBean){this.springBean=springBean;}//利用ApplicationContext 從spring容器中獲得springBean;
//Spring有兩個核心介面BeanFactory和ApplicationContext,其中ApplicationContext是BeanFactory的子介面,
//它們代表了Spring容器,Spring容器是產生Bean的工廠,用於管理容器中的Bean。
public NonSpringClass (){//ApplicationContext acx = new ("applicationContext.xml");
ApplicationContext acx = new ("src/WEB-INF/applicationContext.xml");
springBean=(SpringBean)acx.getBean("springBean");}}調用這個類的代碼:
import com.NonSpringClass;
public class TestCode {
private NonSpringClass nonSpringClass;
//這樣nonSpringClass里將包含Spring容器創建的springBean}}
⑸ web開發中容器一啟動就載入web.xml嗎
是的,web容器一啟動就會載入web.xml,從配置文件的名稱就可以很明顯看出來。
1 、啟動一個 WEB
項目的時候, WEB 容器會去讀取它的配置文件 web.xml
,讀取 <listener> 和 <context-param>
兩個結點。
2 、緊急著,容創建一個 ServletContext
( servlet 上下文),這個 web 項目的所有部分都將共享這個上下文。
3 、容器將 <context-param>
轉換為鍵值對,並交給 servletContext 。
4 、容器創建 <listener>
中的類實例,創建監聽器。
⑹ java web開發結合spring框架問題
1.我覺得層定義介面意義不大!
2.spring將你的注入到容器裡面了,這個默認的是單例的,也就是說,每次spring都得到的是同一個對象。如果你不設置lazy的話,在web容器啟動的時候,spring就會對對象初始化。
3.首先,你要在action中注入TestServiceImpl,action中需要有setTestService方法(或者註解方式)注入介面,spring通過jdk的動態代理去調用相對應的實現方法。service中同樣需要注入TestDAOImpl
並在service中生存setTestDAO(或者註解方式)注入介面,然後調用介面的方法。這個與action調用service相同!
⑺ web容器怎麼載入ocx
在HTML頁面中使用ActiveX控制項包含三個基本操作:將控制項放入HTML中;將該控制項下載給用戶;在用戶機器上安裝該控制項。如果只是針對IE用戶,在HTML中插入ActiveX控制項就比較簡單;如果同時兼顧IE和Netscape用戶,則要做更多工作。大家知道,HTML文件由文本和各種標志 (tags)組成,ActiveX 控制項對於IE在HTML中的標志是<OBJECT>,該標記有幾個重要的參數特性,它們是:
1.ID:為控制項提供一個標識名稱,為HTML代碼提供一種訪問該控制項的方式。
2.CLASSID:是該控制項唯一的UUID,告訴IE裝入哪個對象。如果使用已經開發好的控制項,它的CLASSID可以通過調用Win95或NT下的應用Regedit來查找。從開始菜單中運行該程序,展開HKEY_CLASSES_ROOT項,可以看到按字母順序排列的注冊表,找到需要使用的控制項名,例如WClnt,展開時可看到一個CLSID文件夾,裡面就是該控制項的CLASSID。
如果是自己用VC開發控制項,該UUID可以在ActiveX控制項項目中的ODL(對象描述庫)文件中找到;通過查看控制項的類信息注釋來定位特定控制項的UUID,例如,要找到CMyControl控制項的UUID,則需要找到以下代碼:
//ClassinformationforCMyControl
[uuid(051C4748-1262-11D2-87C1-00A024D948FB),
licensed,
helpstring("CmyControlControl"),control]
uuid後面括弧中的內容就是該控制項的UUID。
3.CODEBASE:如果在用戶機器上沒有控制項的當前版本,該參數告訴用戶瀏覽器在哪裡可找到要下載的控制項和最新版本號.當控制項作了修改後,可以更改版本號強制用戶重新下載。
⑻ web容器有幾種作用域如何防止sql注入
1、打開Active Directory用戶和計算機>點擊查看菜單>點擊高級功能;2、右擊你需要刪除的容器>選擇屬性;3、打開對象選項卡,去掉防止對象被意外刪除選項,點擊確定;4、再右擊刪除即可。
⑼ web容器啟動初始化完 SpringIOC 實例化完bean 項目啟動完成,關於實例化問題
Class.forName("beanClassName"); 這個跟spring ioc木有關系了!因為這個是java語言反射的特性!就像男人就是陽性!如果你木有記錯的話應該知道Java默認一個空構造函數!就是根據這個來反射得到bean實例!
大量的框架都是使用了這個特性才支持了動態裝載一個class來完成了,對象最大化管理!但是反射消耗性能也是比較高的!
種方式是:光熱轉換(太陽能熱水器);光電轉換(太
⑽ struts2的action每次訪問都重新創建一個對象,那spring的ioc是怎麼實現注入的呢
在spring的配置文件中配置各個java bean 的時,可以根據實際情況配置該bean是單態bean還是多態bean,充當action的bean一般都配置成單態的,啟動web伺服器的時候,IOC容器載入spring配置文件,然後生成各個bean的實例,同時各個bean之間的依賴關系也已經建立了。